============================================
译者:yuanlulu
http://blog.csdn.net/yuanlulu
版权没有,但是转载请保留此段声明
============================================
RTC内核文档 英文原文地址:http://lxr.linux.no/linux+v2.6.38/Documentation/rtc.txt
用户空间使用RTC的例程在:http://lxr.linux.no/linux+v2.6.38/Documentation/rtc.txt#L216
Real Time Clock (RTC) Drivers for Linux
=======================================
Linux有两个基本兼容的用户空间RTC API家族:
*/dev/rtc 这是PC系统提供的兼容接口,不适用于非x86的系统
*/dev/rtc0 /dev/rtc1 这是大部分系统支持的形式。
虽然所有的RTC适用同样的API和RTC架构交互,但是硬件提供的功能并不一样。
比如不是所有的RTC都产生中断,所以它们不能做闹钟定时。
(在fedora 上/dev/rtc是一个指向/dev/rtc0的链接)
老式PC/AT兼容驱动:/dev/rtc
----------------------------------------
/dev/rtc(主设备号10,次设备号135,只读字符设备)的中断以unsigned int的格式报告。最低的两字节包含中断类型(
update-done, alarm-rang, or periodic),
剩下的字节包含自上次读取以来中断的次数。如果使能了proc文件系统,在/proc/driver/rtc下能读到中断的状态信息。由于驱动占有了锁,所以同一时间只能有
一个进程占有/dev/rtc。
用户进程可以使用read(2)或者select(2)监视/dev/rtc-它们都将阻塞在设备节点上直到下一个中断的到来。
只有root用户能在dev/rtc上使用大于64HZ的中断。这个值可以通过往/proc/sys/dev/rtc/max-user/freq写入新的值来改变。记住中断处理函数应该尽可能简短。
内核使用额外的代码来和RTC进行同步-内核每11分钟就将自己的时间写回CMOS。在回写的时候内核会关闭RTC的周期中断,
所以依赖RTC周期中断的重要工作需要特别注意这一点。如果你的内核不和RTC进行同步,内核不会访问RTC,你可以把RTC做其它的用处。
中断的频率是通过ioctl(2)调用
/include/linux/rtc.h中的命令来设置的。
新式的“RTC class”接口:/dev/rtcN
----------------------------------------------
由于linux支持的一些非ACPI和非PC平台有不止一个RTC,所以需要更具有可移植性的解决方案。
一种新的“RTC类”框架就是为此而生的,它支持三类用户空间接口:
*/dev/rtcN 和老式的/dev/rtc接口大体相同。
*/sys/class/rtc/rtcN sysfs支持只读的访问RTC属性。
*
/proc/driver/rtc 第一个RTC(rtc0)可以从procfs中暴露自己的更多信息(比sysfs多)。
新的RTC class框架支持多种RTC,包括片上RTC和使用i2c、spi等接口的独立芯片。甚至支持在最新
的PC上通过ACPI暴露的特性。
新的框架不再受"每个系统一个RTC”的约束。比如系统中可以有一个电池供电的低功耗i2c RTC芯片
和一个高性能的片上RTC。系统可以从外置的RTC读取时间,其它的任务或许需要从高性能的片内RTC。
SYSFS 接口
------
sysfs接口在
/sys/class/rtc/rtcN 下,可以直接访问。所有的数据和时间都是RTC的时区决定的,
而不是系统时间的时区
date: 日期:年月日
hctosys: 1:RTC在系统启动的时候通过
CONFIG_RTC_HCTOSYS设置系统时间
0:其它
max_user_freq: 一般用户(不是root)能从RTC申请的最大中断速率。
name: 映射到这个目录的RTC的名字
since_epoch: 和c函数time返回的值意义是一样的。
time: 时分秒。
wakearm: 下一次系统唤醒事件的时间点。这个唤醒事件是一次性的,所以要多次唤醒的话需要在每次
唤醒后重新设置。格式是下次唤醒的
since_epoch值,或者在开头有一个“+”号的话,表示
未来多少秒后发生唤醒事件。
IOCTL接口
--------------
/dev/rtc支持的ioctl()接口同样支持新的RTC框架。
* RTC_RD_TIME, RTC_SET_TIME 读取和设置时间。传递时间的参数是
struct rtc_time结构体。
* RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ alarm中断的开启、关闭、设置、读取。
如果RTC和某个中断线相连,
它可以在未来24小时内的某个时间段内产生中断。
(建议优先使用
RTC_WKALM_*
)
* RTC_WKALM_SET, RTC_WKALM_RD 设置和读取 wakeup alarm触发的时间点。wakeup alarm和alrm
中断唯一不同的是wakeup alrm可以申请超过24小时的定时中断。
*
RTC_UIE_ON, RTC_UIE_OFF 更新中断,每秒钟触发一次(更新的时候触发,因此每秒一次)。
* RTC_PIE_ON, RTC_PIE_OFF, RTC_IRQP_SET, RTC_IRQP_READ 周期中断的开启、关闭、设置、读取。
周期中断的频率必须是2^N(N>= 1),大于64的频率只有root用户才能设置。
(
RTC_AIE_ON, RTC_AIE_OFF可以开启和关闭alarm和wake alarm的功能)
yuanlulu的补充:
* RTC_RD_TIME, RTC_SET_TIME的参数是一个struct rtc_time的指针。它的各个成员的含义和
struct tm是一样的。
struct rtc_time {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */
struct rtc_time time; /* time the alarm is set to */
};
};
只是
wake_alarm没有
时间限制,可以指定未来任意时刻发生中断。
struct rtc_wkalrm {
unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */
unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */
struct rtc_time time; /* time the alarm is set to */
};
*
RTC_ALM_SET, RTC_ALM_READ 的传递参数也是
struct rtc_time
的指针,但只有时分秒的部分有效。时分秒
这三个成员代表24小时以内的时间点。比如当前时间是13:00:00,而传入的参数是14:00:00,则意味着定时中断
将在一小时后发生。而如果传入的参数是12:00:00,则意味着明天中午发生中断。总之,alarm 中断不能超过
24小时。
*
RTC_IRQP_SET, RTC_IRQP_READ 周期中断的参数是中断频率,参数必须是2^N(N>=1),也就是说
设置的周期中断必须大于2。并且只有root用户可以设置64HZ以上的频率。
RTC的中断方式有三类:
1.更新中断,也就是RTC的时间更新的时候触发的中断。RTC每秒钟更新一次,所以更新中断的频率就是1。
2.周期中断。频率可以设置为2^N(N>=1)。注意周期中断频率不可设置为1,否则会被忽略。
3. alarm/wake alarm。这两个中断内部实现是一样的,只不过前者只能指定24小时内的某一时刻触发中断,后者没有限制。
中断被触发后,可以从RTC设备节点中读取到一个unsigned long数据,最低两比特表示中断的类型。各bit的定义如下:
/* interrupt flags */
#define RTC_IRQF 0x80 /* any of the following is active */
#define RTC_PF 0x40 //周期中断
#define RTC_AF 0x20 //定时中断(alarm和wakeup alarm中断)
#define RTC_UF 0x10 //更新中断
#define RTC_IRQF 0x80 /* any of the following is active */
#define RTC_PF 0x40 //周期中断
#define RTC_AF 0x20 //定时中断(alarm和wakeup alarm中断)
#define RTC_UF 0x10 //更新中断
再说RTC中断:RTC的中断概念和内核中的中断不是一回事,没有中断回调函数。但是在设备节点上使用select和read
睡眠的函数会被唤醒,这就是RTC中断的功能。
另外RTC的设备节点,同一时刻只允许一个用户打开。不可能两个用户同时打开同一个RTC设备设备节点。
经过测试,有以下结论:
1.更新中断(1HZ)和周期中断可以同时开启。
2.周期中断可以和alarm中断同时开启。
3.alarm中断不可以和wakeup alarm中断同时开启,因为他们两个在内核中就是一回事。
4..RTC_WKALM_SET不必设置struct rtc_wkalrm的enabled成员,只在读取的时候才需要这个成员。
猜测:更新中断和可以和alarm中断同时开启。
从RTC设备节点读取到的数据,包含了上次读取以来发生中断的次数(包括所有类型的中断)。
低字节会置位发生的所有中断类型。