认识rtc节点
proc下的rtc节点的位置是: /proc/driver/rtc。 该节点可以清晰的显示出当前的时间,当前的日期,alarm的时间,日期,alarm是否使能等详细信息。在分析代码之前先认识一下。
代码语言:javascript复制root@test:test # cat /proc/driver/rtc
rtc_time : 06:25:56 //当前的时间
rtc_date : 2012-01-12 //当前的日期
alrm_time : 05:04:36 //alarm的时间
alrm_date : 2033-04-23 //alarm的日期
alarm_IRQ : no //alarm IRQ是否使能
alrm_pending : no //alarm pending是否使能
update IRQ enabled : no //update IRQ是否使能
periodic IRQ enabled : no //periodic(周期性)IRQ是否使能
periodic IRQ frequency : 1 //periodic IRQ频率
max user IRQ frequency : 64 //periodic IRQ最大的频率
24hr : yes //24小时制
在认识了rtc节点之后,接下来分析代码。
rtc-proc.c
代码语言:javascript复制void rtc_proc_add_device(struct rtc_device *rtc)
{
if (is_rtc_hctosys(rtc)) //判断是否用rtc设备设置系统时间
proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); //如果是,则创建proc节点
}
如下是is_rtc_hctosys的实现:
代码语言:javascript复制#if defined(CONFIG_RTC_HCTOSYS_DEVICE)
static bool is_rtc_hctosys(struct rtc_device *rtc)
{
int size;
char name[NAME_SIZE];
size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id);
if (size > NAME_SIZE)
return false;
return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); //也就是比较rtc设备与内核config中配置的是否一样。
}
#else
static bool is_rtc_hctosys(struct rtc_device *rtc)
{
return (rtc->id == 0);
}
#endif
而此函数是通过内核配置: CONFIG_RTC_HCTOSYS_DEVICE决定的。 可以通过kmconfig查看该配置的详细信息,如下:
代码语言:javascript复制CONFIG_RTC_HCTOSYS_DEVICE:
│ The RTC device that will be used to (re)initialize the system
│ clock, usually rtc0. Initialization is done when the system
│ starts up, and when it resumes from a low power state. This
│ device should record time in UTC, since the kernel won't do
│ timezone correction.
│
│ The driver for this RTC device must be loaded before late_initcall
│ functions run, so it must usually be statically linked.
│
│ This clock should be battery-backed, so that it reads the correct
│ time when the system boots from a power-off state. Otherwise, your
│ system will need an external clock source (like an NTP server).
│
│ If the clock you specify here is not battery backed, it may still
│ be useful to reinitialize system time when resuming from system
│ sleep states. Do not specify an RTC here unless it stays powered
│ during all this system's supported sleep states.
大概意识是当系统启动时,rtc设备通常被用来设置系统时间。
如下是rtc_proc_fops的结构:
代码语言:javascript复制static const struct file_operations rtc_proc_fops = {
.open = rtc_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = rtc_proc_release,
};
当系统打开这个文件的时候就调用到open函数,这都是proc文件系统的执行过程,不是这部分的重点,跳过。
代码语言:javascript复制static int rtc_proc_open(struct inode *inode, struct file *file)
{
int ret;
struct rtc_device *rtc = PDE_DATA(inode); //获得rtc设备结构
if (!try_module_get(THIS_MODULE))
return -ENODEV;
ret = single_open(file, rtc_proc_show, rtc); //调用顺序文件结构初始化
if (ret)
module_put(THIS_MODULE);
return ret;
}
当cat /proc/driver/rtc的时候就调用到read函数,然后最终调用到rtc_proc_show函数。
代码语言:javascript复制static int rtc_proc_show(struct seq_file *seq, void *offset)
{
int err;
struct rtc_device *rtc = seq->private;
const struct rtc_class_ops *ops = rtc->ops;
struct rtc_wkalrm alrm;
struct rtc_time tm;
err = rtc_read_time(rtc, &tm); //读取当前的时间
if (err == 0) {
seq_printf(seq,
"rtc_timet: d:d:dn"
"rtc_datet: d-d-dn",
tm.tm_hour, tm.tm_min, tm.tm_sec,
tm.tm_year 1900, tm.tm_mon 1, tm.tm_mday);
}
err = rtc_read_alarm(rtc, &alrm); //读取alarm时间
if (err == 0) {
seq_printf(seq, "alrm_timet: "); //alarm时间
if ((unsigned int)alrm.time.tm_hour <= 24)
seq_printf(seq, "d:", alrm.time.tm_hour);
else
seq_printf(seq, "**:");
if ((unsigned int)alrm.time.tm_min <= 59)
seq_printf(seq, "d:", alrm.time.tm_min);
else
seq_printf(seq, "**:");
if ((unsigned int)alrm.time.tm_sec <= 59)
seq_printf(seq, "dn", alrm.time.tm_sec);
else
seq_printf(seq, "**n");
seq_printf(seq, "alrm_datet: "); //alarm日期
if ((unsigned int)alrm.time.tm_year <= 200)
seq_printf(seq, "d-", alrm.time.tm_year 1900);
else
seq_printf(seq, "****-");
if ((unsigned int)alrm.time.tm_mon <= 11)
seq_printf(seq, "d-", alrm.time.tm_mon 1);
else
seq_printf(seq, "**-");
if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31)
seq_printf(seq, "dn", alrm.time.tm_mday);
else
seq_printf(seq, "**n");
seq_printf(seq, "alarm_IRQt: %sn",
alrm.enabled ? "yes" : "no"); //alarm IRQ是否使能
seq_printf(seq, "alrm_pendingt: %sn",
alrm.pending ? "yes" : "no"); //alarm pending是否使能
seq_printf(seq, "update IRQ enabledt: %sn",
(rtc->uie_rtctimer.enabled) ? "yes" : "no"); //update IRQ是否使能
seq_printf(seq, "periodic IRQ enabledt: %sn",
(rtc->pie_enabled) ? "yes" : "no"); //periodic IRQ是否使能
seq_printf(seq, "periodic IRQ frequencyt: %dn",
rtc->irq_freq); //periodic IRQ频率
seq_printf(seq, "max user IRQ frequencyt: %dn", //最大的频率
rtc->max_user_freq);
}
seq_printf(seq, "24hrtt: yesn");
if (ops->proc)
ops->proc(rtc->dev.parent, seq); //驱动是否支持proc,一般驱动没有实现。
return 0;
}
可以使用如下的方法卸载/proc/driver/rtc
代码语言:javascript复制void rtc_proc_del_device(struct rtc_device *rtc)
{
if (is_rtc_hctosys(rtc))
remove_proc_entry("driver/rtc", NULL);
}