Linux驱动 | Linux内核 RTC时间架构-深入linux内核架构
Linux驱动 | Linux内核 RTC时间架构
作者:土豆居士 2022-10-08 11:57:30系统 Linux 在瑞芯微的系统中,安卓部分程序其实最终也是依赖**/sys/class/rtc/rtc0** 下的文件节点实现时间管理功能的。一、Linux 时间操作命令 :date、hwclock
Linux时间有两个:系统时间(Wall Time), RTC时间。
1.系统时间(WT):
由Linux系统软件维持的时间,通过Linux命令date查看:
rk3568_r:/ Wed Sep 21 03:05:21 GMT 2022获取到的就是系统时间
2.RTC时间:
这个时间来自我们设备上的RTC芯片,通过Linux命令hwclock可以读取:
rk3568_r:/ Wed Sep 21 03:05:24 20220.000000 seconds我们通过man查看date和hwclock的介绍:
命令说明
1)date
DESCRIPTION Display the current time in the given FORMAT, or set the system date.
2)hwclock
DESCRIPTION hwclockisa tool for accessing the Hardware Clock.It can: display the Hardware Clock time; set the Hardware Clock to a specified time; set the Hardware Clock from theSystemClock;settheSystem Clock from the Hardware Clock; compensate for Hardware Clock drift; correct the System Clock timescale; setthekernel'stime‐ zone,NTPtimescale,andepoch(Alphaonly);compare the System and Hardware Clocks; and predict future Hardware Clock values based on its drift rate. Since v2.26 important changes were made to the --hctosys function and the--direc‐ tisaoption,andanewoption--update-drift was added.See their respective descriptions below.接下来,通过代码看下两者的关系。
二、RTC时间框架
框架如图:
从该架构可得:
Hardware:提供时间信息(time&alarm),通过一定的接口(比如I2C)和RTC Driver进行交互Driver:完成硬件的访问功能,提供访问接口,以驱动的形式驻留在系统class.c:驱动注册方式由class.c:文件提供。驱动注册成功后会构建rtc_device结构体表征的rtc设备,并把rtc芯片的操作方式存放到rtc设备的ops成员中interface.c:文件屏蔽硬件相关的细节,向上提供统一的获取/设置时间或Alarm的接口rtc-lib.c:文件提供通用的时间操作函数,如rtc_time_to_tm、rtc_valid_tm等rtc-dev.c:文件在/dev/目录下创建设备节点供应用层访问,如open、read、ioctl等,访问方式填充到file_operations结构体中hctosys.c/rtc-sys.c/rtc-proc.c:将硬件时钟写给 wall time下面我们从底层往上层来一步步分析。
1、rtc_class_ops 填充
驱动主要工作是填充 rtc_class_ops结构体,结构体描述了RTC芯片能够提供的所有操作方式:
struct rtc_class_ops {int (*open)(struct device *);void (*release)(struct device *);int (*ioctl)(struct device *, unsigned int, unsigned long);int (*read_time)(struct device *, struct rtc_time *);int (*set_time)(struct device *, struct rtc_time *);int (*read_alarm)(struct device *, struct rtc_wkalrm *);int (*set_alarm)(struct device *, struct rtc_wkalrm *);int (*proc)(struct device *, struct seq_file *);int (*set_mmss)(struct device *, unsigned long secs);int (*read_callback)(struct device *, int data);int (*alarm_irq_enable)(struct device *, unsigned int enabled);};实现:
static const struct rtc_class_ops hym8563_rtc_ops = { .read_time= hym8563_rtc_read_time, .set_time= hym8563_rtc_set_time, .alarm_irq_enable = hym8563_rtc_alarm_irq_enable, .read_alarm= hym8563_rtc_read_alarm, .set_alarm= hym8563_rtc_set_alarm,};注册:
hym8563->rtc = devm_rtc_device_register(&client->dev, client->name,&hym8563_rtc_ops, THIS_MODULE);成功的话log:
[0.758774] hym8563_probe()---565----[0.760651] rtc-hym8563 5-0051: rtc information is invalid[0.761666] hym8563_rtc_read_time()---115----1--[0.761681] hym8563_rtc_set_time()---129----1--[0.764235] hym8563_rtc_read_time()---115----1--[0.766425] hym8563_rtc_read_time()---115----1--[0.767439] hym8563_rtc_read_time()---115----1--[0.767619] rtc-hym8563 5-0051: rtc core: registered hym8563 as rtc0[0.768634] hym8563_rtc_read_time()---115----1--[0.768661] rtc-hym8563 5-0051: setting system clock to 2021-01-01 12:00:00 UTC (1609502400)从log可得 5-0051:5表示I2C通道5,0051表示从设备地址 rtc0:注册的rtc设备为rtc0。
2、class.c和RTC驱动注册
class.c文件在RTC驱动注册之前开始得到运行:
static int __init rtc_init(void){rtc_class = class_create(THIS_MODULE, "rtc");rtc_class->suspend = rtc_suspend;rtc_class->resume = rtc_resume;rtc_dev_init();rtc_sysfs_init(rtc_class);return 0;}subsys_initcall(rtc_init);函数功能:
创建名为rtc的class提供PM相关接口suspend/resumertc_dev_init():动态申请/dev/rtcN的设备号rtc_sysfs_init():rtc类具有的device_attribute属性3、RTC驱动注册函数devm_rtc_device_register():
drivers/class.cstruct rtc_device *devm_rtc_device_register(struct device *dev, const char *name, const struct rtc_class_ops *ops, struct module *owner){ struct rtc_device **ptr, *rtc; ptr = devres_alloc(devm_rtc_device_release, sizeof(*ptr), GFP_KERNEL); if (!ptr)return ERR_PTR(-ENOMEM); rtc = rtc_device_register(name, dev, ops, owner); if (!IS_ERR(rtc)) {*ptr = rtc;devres_add(dev, ptr); } else {devres_free(ptr); } return rtc;}rtc_device_register()定义如下:
struct rtc_device *rtc_device_register(const char *name, struct device *dev,const struct rtc_class_ops *ops,struct module *owner){struct rtc_device *rtc;struct rtc_wkalrm alrm;int id, err;id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);rtc->id = id;rtc->ops = ops; rtc->owner = owner;rtc->irq_freq = 1;rtc->max_user_freq = 64;rtc->dev.parent = dev;rtc->dev.class = rtc_class;rtc->dev.release = rtc_device_release; mutex_init(&rtc->ops_lock);spin_lock_init(&rtc->irq_lock);spin_lock_init(&rtc->irq_task_lock);init_waitqueue_head(&rtc->irq_queue); timerqueue_init_head(&rtc->timerqueue);INIT_WORK(&rtc->irqwork, rtc_timer_do_work);rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc);rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc);hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);rtc->pie_timer.function = rtc_pie_update_irq;rtc->pie_enabled = 0; err = __rtc_read_alarm(rtc, &alrm); if (!err && !rtc_valid_tm(&alrm.time))rtc_initialize_alarm(rtc, &alrm); strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);dev_set_name(&rtc->dev, "rtc%d", id); rtc_dev_prepare(rtc); err = device_register(&rtc->dev); rtc_dev_add_device(rtc);rtc_sysfs_add_device(rtc);rtc_proc_add_device(rtc); dev_info(dev, "rtc core: registered %s as %s\n",rtc->name, dev_name(&rtc->dev)); return rtc;}有了 /dev/rtc0后,应用层就可以通过 open/read/ioctl操作RTC设备了,对应与内核的file_operations:
static const struct file_operations rtc_dev_fops = {.owner= THIS_MODULE,.llseek= no_llseek,.read= rtc_dev_read,.poll= rtc_dev_poll,.unlocked_ioctl= rtc_dev_ioctl,.open= rtc_dev_open,.release= rtc_dev_release,.fasync= rtc_dev_fasync,};
4、硬件抽象层interface.c
硬件抽象,即屏蔽具体的硬件细节,为上层用户提供统一的调用接口,使用者无需关心这些接口是怎么实现的。 以RTC访问为例,抽象的实现位于interface.c文件,其实现基于class.c中创建的rtc_device设备。 实现原理,以rtc_set_time为例:
drivers/interface.cint rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm){int err;err = rtc_valid_tm(tm); err = mutex_lock_interruptible(&rtc->ops_lock);if (err)return err; if (!rtc->ops)err = -ENODEV;else if (rtc->ops->set_time)err = rtc->ops->set_time(rtc->dev.parent, tm);mutex_unlock(&rtc->ops_lock);schedule_work(&rtc->irqwork);return err;}
5、rtc在sysfs文件系统中的呈现
之前曾建立过名为rtc的class:
rtc_class = class_create(THIS_MODULE, "rtc");
查看之:
# ls /sys/class/rtc/rtc0# ls -l /sys/class/rtc/ lrwxrwxrwx 1 root root 0 2021-01-01 12:00 rtc0 ->../../devices/platform/fe5e0000.i2c/i2c-5/5-0051/rtc/rtc0
我们系统中只有一个RTC,所以编号为rtc0。
同时发现rtc0文件为指向/sys/devices/platform/fe5e0000.i2c/i2c-5/5-0051/rtc/rtc0的符号链接,
RTC芯片是I2C接口,所以rtc0挂载在I2C的总线上,总线控制器地址fe5e0000,控制器编号为5,RTC芯片作为slave端地址为0x51。
rtc0 设备属性:
drivers/rtc-sysfs.cvoid __init rtc_sysfs_init(struct class *rtc_class){ rtc_class->dev_attrs = rtc_attrs;}static struct attribute *rtc_attrs[] = { &dev_attr_name.attr, &dev_attr_date.attr, &dev_attr_time.attr, &dev_attr_since_epoch.attr, &dev_attr_max_user_freq.attr, &dev_attr_hctosys.attr, NULL,};
对应文件系统中的文件节点:
rk3568_r:/sys/class/rtc # cd rtc0/rk3568_r:/sys/class/rtc/rtc0 # ls -ltotal 0-r--r--r-- 1 root root 4096 2022-09-21 03:56 date-r--r--r-- 1 root root 4096 2022-09-21 03:56 devlrwxrwxrwx 1 root root0 2022-09-21 03:56 device -> ../../../5-0051-r--r--r-- 1 root root 4096 2021-01-01 12:00 hctosys-rw-r--r-- 1 root root 4096 2022-09-21 03:56 max_user_freq-r--r--r-- 1 root root 4096 2022-09-21 03:56 namedrwxr-xr-x 2 root root0 2021-01-01 12:00 power-r--r--r-- 1 root root 4096 2022-09-21 03:56 since_epochlrwxrwxrwx 1 root root0 2022-09-21 03:56 subsystem -> ../../../../../../../class/rtc-r--r--r-- 1 root root 4096 2022-09-21 03:56 time-rw-r--r-- 1 root root 4096 2021-01-01 12:00 uevent-rw-r--r-- 1 root root 4096 2022-09-21 03:56 wakealarmdrwxr-xr-x 2 root root0 2021-01-01 12:00 wakeup8
6、rtc在proc文件系统中的呈现
之前曾rtc0设备加入到了/proc
drivers/class.crtc_device_register(){ --->rtc_proc_add_device(rtc);}void rtc_proc_add_device(struct rtc_device *rtc){ if (is_rtc_hctosys(rtc))proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);}
查看之:
# cat /proc/driver/rtc rtc_time: 03:59:11rtc_date: 2022-09-21alrm_time : 12:00:00alrm_date : 2021-01-02alarm_IRQ : noalrm_pending: noupdate IRQ enabled: noperiodic IRQ enabled: noperiodic IRQ frequency: 1max user IRQ frequency: 6424hr: yes
信息来源:
rtc_proc_fops -->rtc_proc_open-->rtc_proc_show
三、WT时间和RTC时间同步问题
1.WT时间来自于RTC时间,流程是:
上电-->RTC驱动加载-->从RTC同步时间到WT时间
对应驱动代码:
hctosys.c (drivers\rtc)static int __init rtc_hctosys(void){ ......struct timespec tv = {.tv_nsec = NSEC_PER_SEC >> 1,};err = rtc_read_time(rtc, &tm);err = do_settimeofday(&tv);dev_info(rtc->dev.parent,"setting system clock to ""%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec,(unsigned int) tv.tv_sec);......}late_initcall(rtc_hctosys);
late_initcall说明系统在启动流程的后面才会调用该函数去同步时间。
2.瑞芯微时间操作
在瑞芯微的系统中,安卓部分程序其实最终也是依赖**/sys/class/rtc/rtc0** 下的文件节点实现时间管理功能的。
安卓程序会通过AlarmImpl::getTime、AlarmImpl::setTime()方法来获得和设置RTC时间:
frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp122 int AlarmImpl::getTime(int type, struct itimerspec *spec)123 {124 if (static_cast
系统上电后,会先读取文件hctosys中的值,来决定是否将RTC时间写入到wall time:
255 static const char rtc_sysfs[] = "/sys/class/rtc";256 257 static bool rtc_is_hctosys(unsigned int rtc_id)258 {259 android::String8 hctosys_path = String8::format("%s/rtc%u/hctosys",260 rtc_sysfs, rtc_id);261 FILE *file = fopen(hctosys_path.string(), "re");262 if (!file) {263 ALOGE("failed to open %s: %s", hctosys_path.string(), strerror(errno));264 return false;265 }266 267 unsigned int hctosys;268 bool ret = false;269 int err = fscanf(file, "%u", &hctosys);270 if (err == EOF)271 ALOGE("failed to read from %s: %s", hctosys_path.string(),272 strerror(errno));273 else if (err == 0)274 ALOGE("%s did not have expected contents", hctosys_path.string());275 else276 ret = hctosys;277 278 fclose(file);279 return ret;280 }
269行,就是读取文件hctosys中的值,值为1则允许rtc时间写入到wall time,为0或者其他错误则不允许。
因为rtc只要有纽扣电池供电,就会有计时功能,
这是就是为什么,我们的设备关机并重启后,仍然能够显示正确的时间的原因。
【注意目录/sys/class/rtc/下文件是需要有访问权限的】
瑞芯微对文件权限的控制由以下文件提供:
device/rockchip/common/sepolicy/vendor/genfs_contexts
只需要按照对应的格式增加对应文件信息即可。
责任编辑:武晓燕 来源:一口Linux Linux内核架构推荐系统
微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载
语言:中文版系统大小:5.13GB系统类型:Win11微软Win11原版22H2下载_Win11GHOST 免 激活密钥 22H2正式版64位免费下载系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。Win11 64位 Office办公版(免费)优化 1、保留 Edge浏览器。 2、隐藏“操作中心”托盘图标。 3、保留常用组件(微软商店,计算器,图片查看器等)。 5、关闭天气资讯。
Win11 21H2 官方正式版下载_Win11 21H2最新系统免激活下载
语言:中文版系统大小:4.75GB系统类型:Win11Ghost Win11 21H2是微软在系统方面技术积累雄厚深耕多年,Ghost Win11 21H2系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。Ghost Win11 21H2是微软最新发布的KB5019961补丁升级而来的最新版的21H2系统,以Windows 11 21H2 22000 1219 专业版为基础进行优化,保持原汁原味,系统流畅稳定,保留常用组件
windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载
语言:中文版系统大小:5.31GB系统类型:Win11windows11中文版镜像 微软win11正式版简体中文GHOST ISO镜像64位系统下载,微软win11发布快大半年了,其中做了很多次补丁和修复一些BUG,比之前的版本有一些功能上的调整,目前已经升级到最新版本的镜像系统,并且优化了自动激活,永久使用。windows11中文版镜像国内镜像下载地址微软windows11正式版镜像 介绍:1、对函数算法进行了一定程度的简化和优化
微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载
语言:中文版系统大小:5.31GB系统类型:Win11微软windows11正式版GHOST ISO镜像 win11下载 国内最新版渠道下载,微软2022年正式推出了win11系统,很多人迫不及待的要体验,本站提供了最新版的微软Windows11正式版系统下载,微软windows11正式版镜像 是一款功能超级强大的装机系统,是微软方面全新推出的装机系统,这款系统可以通过pe直接的完成安装,对此系统感兴趣,想要使用的用户们就快来下载
微软windows11系统下载 微软原版 Ghost win11 X64 正式版ISO镜像文件
语言:中文版系统大小:0MB系统类型:Win11微软Ghost win11 正式版镜像文件是一款由微软方面推出的优秀全新装机系统,这款系统的新功能非常多,用户们能够在这里体验到最富有人性化的设计等,且全新的柔软界面,看起来非常的舒服~微软Ghost win11 正式版镜像文件介绍:1、与各种硬件设备兼容。 更好地完成用户安装并有效地使用。2、稳定使用蓝屏,系统不再兼容,更能享受无缝的系统服务。3、为
雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载
语言:中文版系统大小:4.75GB系统类型:雨林木风Windows11专业版 Ghost Win11官方正式版 (22H2) 系统下载在系统方面技术积累雄厚深耕多年,打造了国内重装系统行业的雨林木风品牌,其系统口碑得到许多人认可,积累了广大的用户群体,雨林木风是一款稳定流畅的系统,一直以来都以用户为中心,是由雨林木风团队推出的Windows11国内镜像版,基于国内用户的习惯,做了系统性能的优化,采用了新的系统
雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO
语言:中文版系统大小:5.91GB系统类型:Win7雨林木风win7旗舰版系统下载 win7 32位旗舰版 GHOST 免激活镜像ISO在系统方面技术积累雄厚深耕多年,加固了系统安全策略,雨林木风win7旗舰版系统在家用办公上跑分表现都是非常优秀,完美的兼容各种硬件和软件,运行环境安全可靠稳定。win7 32位旗舰装机版 v2019 05能够帮助用户们进行系统的一键安装、快速装机等,系统中的内容全面,能够为广大用户
番茄花园Ghost Win7 x64 SP1稳定装机版2022年7月(64位) 高速下载
语言:中文版系统大小:3.91GB系统类型:Win7欢迎使用 番茄花园 Ghost Win7 x64 SP1 2022.07 极速装机版 专业装机版具有更安全、更稳定、更人性化等特点。集成最常用的装机软件,集成最全面的硬件驱动,精心挑选的系统维护工具,加上独有人性化的设计。是电脑城、个人、公司快速装机之首选!拥有此系统
相关文章
- dellWin8系统之家最新系统推荐
- 如何创建微信群?创建微信群的图文图文详细教程_其它聊天
- 开机打开项,本文教您怎样设置开机打开项
- 在BIOS中找到USB-HDD的办法
- win 10系统:安装显卡出现花屏
- Win8系统注册表打开不了了如何应对?
- WPS中Word五步完成设置书签!
- WinXP如何提高下载速度
- 怎么检测电脑是否支持Win11系统?电脑无法运行Win11怎么办?
- 菜鸟win7双系统安装教程 两个系统都用win7
- WinXP如何设置PPTP/L2TP连接VPN
- Win8设置电源节能模式的办法
- 抢红包软件安全吗?安全运用抢红包软件的3个规范_微信
- 简述联想官方售后重装系统收费吗以及如何重装
- 番茄花园windows 7专业版介绍
- 怎样设置电脑开机密码,本文教您win10怎样设置开机密码
- 如何处理Win8开机提示Invalid Partition Table的问题?
- Win10如何启用设置管理员账户,本文教您如何启用
热门系统
- 1华硕笔记本&台式机专用系统 GhostWin7 32位正式旗舰版2018年8月(32位)ISO镜像下载
- 2深度技术 Windows 10 x86 企业版 电脑城装机版2018年10月(32位) ISO镜像免费下载
- 3电脑公司 装机专用系统Windows10 x86喜迎国庆 企业版2020年10月(32位) ISO镜像快速下载
- 4雨林木风 Ghost Win7 SP1 装机版 2020年4月(32位) 提供下载
- 5深度技术 Windows 10 x86 企业版 六一节 电脑城装机版 版本1903 2022年6月(32位) ISO镜像免费下载
- 6深度技术 Windows 10 x64 企业版 电脑城装机版2021年1月(64位) 高速下载
- 7新萝卜家园电脑城专用系统 Windows10 x64 企业版2019年10月(64位) ISO镜像免费下载
- 8新萝卜家园 GhostWin7 SP1 最新电脑城极速装机版2018年8月(32位)ISO镜像下载
- 9电脑公司Ghost Win8.1 x32 精选纯净版2022年5月(免激活) ISO镜像高速下载
- 10新萝卜家园Ghost Win8.1 X32 最新纯净版2018年05(自动激活) ISO镜像免费下载
热门文章
常用系统
- 1风林火山 GHOST WIN7 SP1 X64 旗舰稳定版 V2023.02 下载
- 2萝卜家园GHOST WIN10 X86 完美装机版v2023.10最新下载
- 3番茄花园 Windows 10 新春特别 极速企业版 2020年2月(32位) ISO镜像快速下载
- 4笔记本&台式机专用系统 Windows10 企业版 版本1903 2021年11月(32位) ISO镜像快速下载
- 5雨林木风 GHOST WIN7 SP1 X64 喜迎国庆版 V2023.10 下载
- 6新萝卜家园Ghost Win8.1 x64 多驱动纯净版2018年06(免激活) ISO镜像免费下载
- 7雨林木风 WIN7 64位经典装机版 V2023.08 下载
- 8Win10 22H2专业版下载_Win10永久激活版下载
- 9深度技术GhostWin10x86全新专业版V2020.05免费下载
- 10番茄花园 Ghost XP SP3 海量驱动装机版 2019年12月 ISO镜像高速下载