hwclock -w 报错

文章目录

  • `hwclock -w` 报错
    • 问题现象
    • 分析
      • 1. hwclock命令分析
      • 2. `/dev/rtc0`驱动节点分析
    • 修改设备树后`hwclock -w`报错没有了,但是系统会重启,原因未知

问题现象

sdm660_64:/ # hwclock -w
hwclock: ioctl 4024700a: Invalid argument

分析

1. hwclock命令分析

hwclock命令是toybox的内建命令,可以修改toybox代码来调试

进入external/toybox目录下修改toybox/toys/other/hwclock.c

diff --git a/toybox/toys/other/hwclock.c b/toybox/toys/other/hwclock.c
index 1d313e3..5d907aa 100644
--- a/toybox/toys/other/hwclock.c
+++ b/toybox/toys/other/hwclock.c
@@ -82,13 +82,25 @@ void hwclock_main()dirtree_read("/sys/class/rtc", rtc_find);if (!TT.fname) TT.fname = "/dev/misc/rtc";}
+    xprintf("fd=%d,TT.fname%s\n", fd, TT.fname);if (fd == -1) fd = xopen(TT.fname, flag);
+    xprintf("fd=%d,TT.fname%s\n", fd, TT.fname);// Get current time in seconds from rtc device. todo: get subsecond timeif (!w) {char *s = s;+      xprintf("RTC_RD_TIME\n");xioctl(fd, RTC_RD_TIME, &tm);
+      xprintf("tm_sec=%d\n", tm.tm_sec);
+      xprintf("tm_min=%d\n", tm.tm_min);
+      xprintf("tm_hour=%d\n", tm.tm_hour);
+      xprintf("tm_mday=%d\n", tm.tm_mday);
+      xprintf("tm_mon=%d\n", tm.tm_mon);
+      xprintf("tm_year=%d\n", tm.tm_year);
+      xprintf("tm_wday=%d\n", tm.tm_wday);
+      xprintf("tm_yday=%d\n", tm.tm_yday);
+      xprintf("tm_isdst=%d\n", tm.tm_isdst);if (TT.utc) s = xtzset("UTC0");if ((time = mktime(&tm)) < 0) error_exit("mktime failed");if (TT.utc) {
@@ -108,7 +120,17 @@ void hwclock_main()/* The value of tm_isdst is positive if daylight saving time is in effect,* zero if it is not and negative if the information is not available.* todo: so why isn't this negative...? */
+    xprintf("RTC_SET_TIME\n");tm.tm_isdst = 0;
+    xprintf("tm_sec=%d\n", tm.tm_sec);
+    xprintf("tm_min=%d\n", tm.tm_min);
+    xprintf("tm_hour=%d\n", tm.tm_hour);
+    xprintf("tm_mday=%d\n", tm.tm_mday);
+    xprintf("tm_mon=%d\n", tm.tm_mon);
+    xprintf("tm_year=%d\n", tm.tm_year);
+    xprintf("tm_wday=%d\n", tm.tm_wday);
+    xprintf("tm_yday=%d\n", tm.tm_yday);
+    xprintf("tm_isdst=%d\n", tm.tm_isdst);xioctl(fd, RTC_SET_TIME, &tm);} else if (toys.optflags & FLAG_s) {tzone.tz_minuteswest = timezone / 60 - 60 * daylight;

执行编译命令

make toybox -j4

将本地编译的toybox push到手机里面

# adb push toybox /system/bin/toybox2# adb shell
sdm660_64:/ # toybox2 hwclock -w
fd=-1,TT.fname/dev/rtc0
fd=3,TT.fname/dev/rtc0
RTC_SET_TIME
tm_sec=49
tm_min=45
tm_hour=19
tm_mday=24
tm_mon=7
tm_year=121
tm_wday=2
tm_yday=235
tm_isdst=0
hwclock: ioctl 4024700a: Invalid argument

由此可以判定是/dev/rtc0这个驱动节点有问题。并且是在进行ioctl RTC_SET_TIME时发生的问题。

2. /dev/rtc0驱动节点分析

观察进行ioctl RTC_SET_TIME时发生了什么。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qa8YNNY6-1629809627988)(https://note.youdao.com/yws/res/b/WEBRESOURCE7b9c259a0e11b0e7db40166ff22225eb)]

这里可以看到,调用到了rtc_set_time函数

修改如下代码,增加debug log

diff --git a/msm-4.4/drivers/rtc/interface.c b/msm-4.4/drivers/rtc/interface.c
index 9cad172..7bf4d88 100644
--- a/msm-4.4/drivers/rtc/interface.c
+++ b/msm-4.4/drivers/rtc/interface.c
@@ -61,19 +61,25 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm){int err;+    dev_warn(&rtc->dev, "tm value: %d-%d-%d %d:%d:%d\n",
+        tm->tm_year + 1900, tm->tm_mon + 1,
+        tm->tm_mday, tm->tm_hour, tm->tm_min,
+        tm->tm_sec);err = rtc_valid_tm(tm);if (err != 0)return err;err = mutex_lock_interruptible(&rtc->ops_lock);
+    dev_warn(&rtc->dev, "mutex_lock_interruptible,err=%d\n", err);if (err)return err;if (!rtc->ops)err = -ENODEV;
-       else if (rtc->ops->set_time)
+       else if (rtc->ops->set_time) {
+        dev_warn(&rtc->dev, "err = rtc->ops->set_time(rtc->dev.parent, tm);\n");err = rtc->ops->set_time(rtc->dev.parent, tm);
-       else if (rtc->ops->set_mmss64) {
+    } else if (rtc->ops->set_mmss64) {time64_t secs64 = rtc_tm_to_time64(tm);err = rtc->ops->set_mmss64(rtc->dev.parent, secs64);
@@ -82,6 +88,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)err = rtc->ops->set_mmss(rtc->dev.parent, secs64);} elseerr = -EINVAL;
+    dev_warn(&rtc->dev,"ifxxx err=%d\n", err);pm_stay_awake(rtc->dev.parent);mutex_unlock(&rtc->ops_lock);
diff --git a/msm-4.4/drivers/rtc/qpnp-rtc.c b/msm-4.4/drivers/rtc/qpnp-rtc.c
index bafcebb..8baf15d 100644
--- a/msm-4.4/drivers/rtc/qpnp-rtc.c
+++ b/msm-4.4/drivers/rtc/qpnp-rtc.c
@@ -113,6 +113,7 @@ qpnp_rtc_set_time(struct device *dev, struct rtc_time *tm)value[2] = (secs >> 16) & 0xFF;value[3] = (secs >> 24) & 0xFF;+       dev_err(dev, "Seconds value to be written to RTC = %lu\n", secs);dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);spin_lock_irqsave(&rtc_dd->alarm_ctrl_lock, irq_flags);

修改后的rtc_set_time函数

int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{int err;dev_warn(&rtc->dev, "tm value: %d-%d-%d %d:%d:%d\n",tm->tm_year + 1900, tm->tm_mon + 1,tm->tm_mday, tm->tm_hour, tm->tm_min,tm->tm_sec);err = rtc_valid_tm(tm);if (err != 0)return err;err = mutex_lock_interruptible(&rtc->ops_lock);dev_warn(&rtc->dev, "mutex_lock_interruptible,err=%d\n", err);if (err)return err;if (!rtc->ops)err = -ENODEV;else if (rtc->ops->set_time) {dev_warn(&rtc->dev, "err = rtc->ops->set_time(rtc->dev.parent, tm);\n");err = rtc->ops->set_time(rtc->dev.parent, tm);} else if (rtc->ops->set_mmss64) {time64_t secs64 = rtc_tm_to_time64(tm);err = rtc->ops->set_mmss64(rtc->dev.parent, secs64);} else if (rtc->ops->set_mmss) {time64_t secs64 = rtc_tm_to_time64(tm);err = rtc->ops->set_mmss(rtc->dev.parent, secs64);} elseerr = -EINVAL;dev_warn(&rtc->dev,"ifxxx err=%d\n", err);pm_stay_awake(rtc->dev.parent);mutex_unlock(&rtc->ops_lock);/* A timer might have just expired */schedule_work(&rtc->irqwork);return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time);

刷机后复现问题,抓取log

# adb shell
sdm660_64:/ # logcat -b kernel | grep -i rtc
01-01 07:28:27.330     0     0 I msm_serial c170000.serial: uartclk = 1843200
01-01 07:28:27.364     0     0 I msm_serial c16f000.serial: uartclk = 19200000
01-01 07:28:27.384     0     0 I msm_serial c1b0000.serial: uartclk = 19200000
01-01 07:28:28.790     0     0 I qcom,qpnp-rtc 800f000.qcom,spmi: qcom,pm660@0:qcom,pm660_rtc: rtc core: registered qpnp_rtc as rtc0
01-01 07:28:29.515     0     0 I qcom,qpnp-rtc 800f000.qcom,spmi: qcom,pm660@0:qcom,pm660_rtc: setting system clock to 1970-01-01 07:28:29 UTC (26909)
08-24 20:07:46.101     0     0 W rtc0    : tm value: 2021-8-24 20:7:46
08-24 20:07:46.101     0     0 W rtc0    : mutex_lock_interruptible,err=0
08-24 20:07:46.105     0     0 W rtc0    : ifxxx err=-22
08-24 20:15:03.147     0     0 W rtc0    : tm value: 2021-8-24 20:15:3
08-24 20:15:03.147     0     0 W rtc0    : mutex_lock_interruptible,err=0

mutex_lock_interruptible,err=0ifxxx err=-22这两个log,但是没有err = rtc->ops->set_time(rtc->dev.parent, tm);

说明没有走这个if语句

else if (rtc->ops->set_time) {dev_warn(&rtc->dev, "err = rtc->ops->set_time(rtc->dev.parent, tm);\n");err = rtc->ops->set_time(rtc->dev.parent, tm);

这个rtc->ops->set_time似乎是空的

但是根据上面log中的qcom,qpnp-rtc两行log(这里再列在下面方便表述),高通的qcom,qpnp-rtc驱动已经注册了rtc0

01-01 07:28:28.790     0     0 I qcom,qpnp-rtc 800f000.qcom,spmi: qcom,pm660@0:qcom,pm660_rtc: rtc core: registered qpnp_rtc as rtc0
01-01 07:28:29.515     0     0 I qcom,qpnp-rtc 800f000.qcom,spmi: qcom,pm660@0:qcom,pm660_rtc: setting system clock to 1970-01-01 07:28:29 UTC (26909)

根据高通的qpnp_rtc驱动代码看

static int qpnp_rtc_probe(struct platform_device *pdev)
{const struct rtc_class_ops *rtc_ops = &qpnp_rtc_ro_ops;...//省略if (rtc_dd->rtc_write_enable == true)rtc_ops = &qpnp_rtc_rw_ops;...//省略/* Register the RTC device */rtc_dd->rtc = rtc_device_register("qpnp_rtc", &pdev->dev,rtc_ops, THIS_MODULE);if (IS_ERR(rtc_dd->rtc)) {dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n",__func__, PTR_ERR(rtc_dd->rtc));rc = PTR_ERR(rtc_dd->rtc);goto fail_rtc_enable;}...//省略
}

这个rtc_dd->rtc_write_enable很关键,如果是true.set_time = qpnp_rtc_set_time才会被注册

根据上面的代码可以看出,当设备树中的qcom,qpnp-rtc-write被设置为true时,满足rtc_dd->rtc_write_enable == true的条件。

按如下方式修改设备树,即可

diff --git a/msm-4.4/arch/arm/boot/dts/qcom/msm-pm660.dtsi b/msm-4.4/arch/arm/boot/dts/qcom/msm-pm660.dtsi
index 56f8bfb..09b64eb 100755
--- a/msm-4.4/arch/arm/boot/dts/qcom/msm-pm660.dtsi
+++ b/msm-4.4/arch/arm/boot/dts/qcom/msm-pm660.dtsi
@@ -168,7 +168,7 @@compatible = "qcom,qpnp-rtc";#address-cells = <1>;#size-cells = <1>;
-                       qcom,qpnp-rtc-write = <0>;
+                       qcom,qpnp-rtc-write = <1>;qcom,qpnp-rtc-alarm-pwrup = <0>;qcom,pm660_rtc_rw@6000 {

修改设备树后hwclock -w报错没有了,但是系统会重启,原因未知

高通平台 Android9 adb shell “hwclock -w“ 报错相关推荐

  1. dos命令行输入adb shell命令为什么报错

    在命令行(就是开始--运行--输入cmd)模式下输入adb shell命令一般会报两种错误,一是"adb不是内部命令或外部命令,也不是可运行的程序或批处理文件",二是"e ...

  2. 高通android充电常用问题,高通平台android9.0充电电量,充电指示灯以及充电图标读取分析...

    第一部分     qpnq-qg.c static int qpnp_qg_probe(struct platform_device *pdev) { ....... INIT_WORK(&c ...

  3. 高通平台(Qualcomm) Android 10 /11/12 user版本默认打开adb 调试小结

    1.流程 USB插入接收广播授权->建立adb连接服务->执行adb 命令 2.adb相关属性 ro.secure = 0 开启root权限 ro.adb.secure = 1 1开启ad ...

  4. 高通平台android开发总结

    http://www.cnblogs.com/yuzaipiaofei/archive/2012/07/24/4124179.html 1.高通平台android开发总结 1.1 搭建高通平台环境开发 ...

  5. 高通平台android 环境配置编译及开发经验总结

    完全转自:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...

  6. 高通平台android开发总结 .

    http://blog.csdn.net/mirkerson/article/details/7691029 http://blog.csdn.net/mirkerson/article/detail ...

  7. 高通平台android 环境配置编译及开发经验总结【转】

    1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通开发板上烧录文件系统 建立高通平台开发环境 高通平台,android和 modem 编译流程分析 高通平台 7620 启动流 ...

  8. 高通平台sensor学习

    刚入行驱动时最先接触调试的外设模块便是sensor,一直都是零零散散的记录,这次终于下定决心对自己所学做一个系统的总结. sensor作为一款常用的外设,虽不起眼但是很多功能确实离不开它.比如我们手机 ...

  9. 高通平台android开发总结 MSM平台上的AMSS

    http://blog.csdn.net/mirkerson/article/details/7691029 MSM平台上的AMSS REX启动分析--基于Qualcomm平台 1.高通平台andro ...

最新文章

  1. MySQL 5.6 Warning - Using a password on the command line interface can be insecur 解决方案
  2. 面向接口编程详解(三)——模式研究
  3. 当硬核动作游戏《怪物猎人》变成了回合制RPG,还会那么好玩吗?
  4. css3学习总结1--CSS3选择器
  5. HP-UNIX操作系统root账号被锁定的两种解决方法
  6. Codeforces Round #712 (Div. 2) D. 3-Coloring 交互 构造
  7. 用数字化数据战略取代数据“收集和管理”
  8. 论文笔记_S2D.71_2020_CVPR_用于自监督单目深度估计的3D packing
  9. 浙江省高考计算机重点知识,2017届浙江省新高考信息技术考试标准
  10. win 10 linux shell,实用工具:Win10下的bash shell打开教程
  11. 前端开发_开发软件Hbuilder简介
  12. 发送、抄送、密送、分别发送、回复、回复全部、转发的区别(一篇文章研究透彻)
  13. 先天八卦图的排列顺序,这样来解释您能接受吗?
  14. 网站管理,网站管理技巧的步骤
  15. 高性能软件系统设计中应该考虑的问题
  16. 希尔排序选择排序时间复杂度分析
  17. 单片机数字钟(调时,调时闪烁,万年历,年月日)超详细解析
  18. 图神经网络与图注意力网络相关知识概述
  19. java按秒查询数据_ClickHouse留存分析工具十亿数据秒级查询方案
  20. JMM(Java Memory Model)

热门文章

  1. 使用python + Fiddler爬取抖音用户下所有视频
  2. 超级课程表如何导入课程 超级课程表怎么导入课程
  3. 北京内推 | 智源人工智能研究院数据智能组招聘全职研究员/算法工程师
  4. mysql数据库麦如何修复_非常规方法,轻松应对Oracle数据库危急异常
  5. 历城职专学前计算机专业,一年之计在于春,不负青春好时节——历城职专学前教育专业2019级技能运动会圆满举行...
  6. el-menu,Collapse 折叠面板,收起后子菜单弹窗popover跟菜单的距离
  7. signal软件如何退出账号_AppStore今日分享 很贵很强大的视频编辑软件
  8. kubeasz 安装K8S 错误解决
  9. 战神遗迹服务器未响应怎么回事,战神遗迹客服在哪 解决方案一览
  10. Java 定时任务配置文件