完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
RTC 简介
RTC 也是时钟需要的时间,记录当前系统时间,对于 Linux 系统而言,时间是非常重要的,使用 Linux 设备的时候也可以查看时间。RTC 是 Linux 的时间系统。 RTC 设备驱动是一个标准的 RTC相关结构 // Linux内核将RTC设备抽象为rtc_device结构体struct rtc_device { struct device dev; // 设备 结构模块 *owner; 内部标识;// ID const struct rtc_class_ops *ops; // RTC 设备操作函数 struct mutex op_lock; 结构 cdev char_dev; // 字符设备 unsigned long flags; 无符号长 irq_data; spinlock_t irq_lock; wait_queue_head_t irq_queue; 结构 fasync_struct *async_queue; 国际中断频率; int max_user_freq; 结构定时器队列头定时器队列; 结构 rtc_timer aie_timer; 结构 rtc_timer uie_rtctimer; 结构 hrtimer pie_timer; /* 亚秒 exp,所以需要 hrtimer */ int pie_enabled; struct work_struct irqwork; /* 某些硬件不支持 UIE 模式 */ int uie_unsupported; /* 设置 RTC 时钟所需的纳秒数。这会影响何时 调用集合操作。偏移量: * - 0.5 秒将调用 RTC 设置为挂钟时间 10.0 秒在 9.5 秒 * - 1.5 秒将调用 RTC 设置为挂钟时间 10.0 秒在 8.5 秒 * - -0.5 s 将调用 RTC 设置为挂钟时间 10.0 s 在 10.5 s */ long set_offset_nsec; 布尔注册; 结构 nvmem_device *nvmem; /* 旧 ABI 支持 */ bool nvram_old_abi; 结构 bin_attribute *nvram; time64_t range_min; timeu64_t range_max; time64_t start_secs; time64_t offset_secs; 布尔 set_start_time; #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL struct work_struct uie_task; 结构 timer_list uie_timer; /* 这些字段受 rtc-》irq_lock 保护 */ unsigned int oldsecs; 无符号整数 uie_irq_active:1; 无符号 int stop_uie_polling:1; 无符号整数 uie_task_active:1; 无符号整数 uie_timer_active:1; #endif }; // RTC 的最底层操作函数集合,编写// 只是最应用用户 的 RTC 函数的设备操作函数,另外提供给设备的file_operations 操作集。 struct rtc_class_ops { int*ioctl)(struct device *, unsigned整数,无符号长); 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_mmss64)(struct device *, time64_t secs); int (*set_mmss)(struct device *, unsigned long secs); int (*read_callback)(struct device *, int data); int (*alarm_irq_enable)(struct device *, unsigned int enabled); int (*read_offset)(struct device *, long *offset); int (*set_offset)(struct device *, long offset); }; // 提供给应用层的file_operations函数集 drivers/rtc/rtc-dev.c 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, }; RTC 全局调用框架 RTC 代码解析 涉及到的目录功能总结 类向linux内核注册中的一个类RTC子系统的一些公共函数。让C提供注册给我们C驱动注册集成到的Linux内核中,C向驱动程序注册了/接口了。 rtc-dev.c:定义了基本的设备文件操作函数,用户程序和RTC驱动的接口函数,这里定义了每个ioctl命令需要调用的函数,还有open,read等。 interface.c 任务需要提供调用的函数。 rtc-sysfs.c:与sysfs有关,提供通过sys文件系统操作pcf8563。 rtc-proc.c:与proc文件系统相关,通过proc文件系统操作pcf8563提供。 hctosys.c:系统起来之后会调用到硬件这个文件中的rtc_hctosys()函数,主要功能是系统起来的时候去读RTC中的时间,然后更新我们的系统时间。 rtc.h:定义了与RTC相关的数据结构。 RTC注册函数解析 //驱动驱动路径:drivers/rtc/class.c struct class *rtc_class; rtc_init -》 rtc_class = class_create(THIS_MODULE, “rtc”); // 创建rtc的class -》 rtc_class-》pm = RTC_CLASS_DEV_PM_OPS; // 提供唤醒唤醒相关接口suspend/resume -》 rtc_dev_init(); // 动态申请/dev/rtcN的设备号 -》 alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, “rtc”); // RTC_DEV_MAX=16 subsys_initcall(rtc_init); // rtc_sysfs_init():rtc类具有device_attribute属性 rtc_device_register -》 id = rtc_device_get_id(dev); // Linux支持多个RTC设备,所以需要为每个设备配置一个ID -》 ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); -》 rtc = rtc_allocate_device(); -》 结构 rtc_device *rtc; -》 rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); // 创建rtc_设备(对象)并 初始化device-》 。..。.. rtc-》dev.class = rtc_class; 。..。.. // rtc_init 创建的等待_class // rtc中相关锁,为rtc设备的初始化 -》 mute(&rtc》ops_lock); -》 spin_lock_init(&rtc-》irq_lock); -》 init_waitqueue_head(&rtc-》irq_queue); // 初始化工作任务rtc_timer -》 timerqueue_init_head(&rtc-》 -》 INIT_WORK(&rtc-》irqwork, rtc_timer_do_work); // 初始化rtc_timer(&rtc_init(&)rt_init( // RTC更新中断 -》 rtc_timer_init(&rtc-》uie_rtctimer, rtc_uie_update_irq, (void *)rtc); // RTC_暂停-》hrtimer_init(&rtc-》pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_R_init; -》 rtc-》pie_timer.function = rtc_pie_update_irq; -》 rtc-》pie_enabled = 0; -》 rtc-》id = id; -》 rtc-》操作=操作;// 满足 RTC 驱动驱动的操作函数 -》 rtc-》owner = owner; -》 rtc-》dev.parent = dev; -》 dev_set_name(&rtc-》dev, “rtc%d”, id); // 设置rtc的dev成员中的name域 -》 __rtc_read_alarm(rtc, &alrm); // 如果(如果设置rr-&&》!erval_tm(&al. rtc_initialize_alarm(rtc, &alrm); -》 rtc_dev_prepare(rtc); // /dev/rtc0的rtc作为字符设备进行 初始化-》 cdev_init(&rtc-》char_dev, &rtc_dev_fops); // rtc_dev_fops接口操作函数结构体 -》 cdev-》ops = fops; -》 cdev_device_add(&rtc-》char_dev, &rtc-》dev); -》 cdev_add(cdev, dev-》devt, 1); // rtc设备作为异常设备添加到系统 生成/dev/rtc0 -》 rtc_proc_add_device(rtc); // /proc/rtc -》 proc_create_single_data(“driver/rtc”, 0, NULL, rtc_proc_show, rtc); // 提供给用户层的接口 static const struct file_operations rtc_dev_fops = { .owner = THIS_MODULE, .llseek = no_llseek, 。 .poll = rtc_dev_poll, .unlocked_ioctl = rtc_dev_ioctl, .open = rtc_dev_open, .release = rtc_dev_release, .fasync = rtc_dev_fasync, }; kernel中__init类型函数位于.init.text的在.initcall中保存的相应函数中,init段的指针值都在启动过程中,根据定义在段中的等级(0~7)从#define core_initcall ( fn) __define_initcall(fn, 1) #define core_initcall_sync(fn) __define_initcall(fn) __define_initcall(fn) , 1s) #define postcore_initcall(fn) __define_initcall(fn, 2) #define postcore_initcall_sync(fn) __define_initcall(fn, 2s) #define arch_initcall(fn) __define_initcall(fn, 3) #define arch_initcall_sync(fn) __define_initcall(fn, 3s) #define subsys_initcall(fn) __define_initcall(fn, 4) #define subsys_initcall_sync(fn) __define_initcall(fn, 4s) #define fs_initcall(fn) __define_initcall(fn, 5) #define fs_initcall_sync(fn) __define_initcall(fn, 5s) #define rootfs_initcall(fn) __define_initcall(fn, rootfs) #define device_initcall(fn) __define_initcall(fn, 6) #define device_initcall_sync(fn) __define_initcall(fn, 6s) #define late_initcall( fn) __define_initcall(fn, 7) #define late_initcall_sync(fn) __define_initcall(fn, 7s) 应用层调用驱动流程解析 rtc_dev_ioctl (struct file *file, unsigned int cmd, unsigned long arg) // drivers/rtc/rtc-dev.c -》 struct rtc_device *rtc = file-》private_data; // 获取到rtc设备 -》 switch (cmd) -》 case RTC_RD_TIME: -》 rtc_read_time // drivers/rtc/interface.c -》 __rtc_read_time -》 rtc-》ops-》read_time(rtc-》dev.parent, tm ); -》 case RTC_SET_TIME: -》 rtc_set_time // drivers/rtc/interface.c -》 rtc_valid_tm(tm); // 检查 // 调用rt参数device中的函数结构体的函数指针//////////////////////////////////////////////////// 调用参数中 的函数指针在RTC驱动中 ops- 》 if (!rtc-》ops) 错误 = -ENOD else if (rtc-》ops-》set_time) err = rtc-》ops-》set_time(rtc-》dev.parent, tm); else if (rtc-》ops-》set_mmss64) { time64_t secs64 = rtc_tm_to_time64(tm); 错误 = rtc-》ops-》set_mmss64(rtc-》dev.parent, secs64); |
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
谁有3566+电池+POE充电的方案,有个项目需要用该功能的主板
437 浏览 0 评论
RK3588的GMAC0与PHY的参考时钟电平匹配问题??????
4425 浏览 1 评论
请问各位大佬,如何解决,瑞芯微 RV1126B 使用 mpp 自带工具 调试时,内核直接报错崩溃!
1802 浏览 0 评论
使用rk3568开发板,核0\\1\\3运行linux,核2运行hal,在核0中怎么关闭核2
2359 浏览 0 评论
2363 浏览 0 评论
/9
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-12-2 10:00 , Processed in 1.457376 second(s), Total 72, Slave 55 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191

淘帖
1792