在arch/arm/plat-samsung/Devs.c文件内,系统定义了RTC平台设备及其资源:
static struct resource s3c_rtc_resource[] = {
[0]= DEFINE_RES_MEM(S3C24XX_PA_RTC,SZ_256),
[1]= DEFINE_RES_IRQ(IRQ_RTC),
[2]= DEFINE_RES_IRQ(IRQ_TICK),
};
struct platform_device s3c_device_rtc = {
.name = "s3c2410-rtc",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_rtc_resource),
.resource = s3c_rtc_resource,
};
因为RTC一共有两个中断源:报警中断和时间节拍中断,所以RTC资源中也相应的定义了两个中断——IRQ_RTC和IRQ_TICK。在arch/arm/mach-s3c24xx/Mach-zhaocj2440.c文件内,系统把RTC平台设备添加到了zhaocj2440_devices数组内:
static struct platform_device *zhaocj2440_devices[]__initdata = {
……
&s3c_device_rtc,
……
};
最后在zhaocj2440_init函数内,通过下列语句把RTC平台设备添加到了总线内:
platform_add_devices(zhaocj2440_devices,ARRAY_SIZE(zhaocj2440_devices));
上面介绍的是RTC平台设备,而它的平台驱动是在drivers/rtc/Rtc-s3c.c文件内定义的:
static struct platform_driver s3c_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = __devexit_p(s3c_rtc_remove),
.suspend = s3c_rtc_suspend,
.resume = s3c_rtc_resume,
.id_table = s3c_rtc_driver_ids,
.driver = {
.name = "s3c-rtc",
.owner = THIS_MODULE,
.of_match_table = s3c_rtc_dt_match,
},
};
由于定义了RTC平台设备列表s3c_rtc_driver_ids,因此平台驱动通过这个列表与平台设备相互匹配:
static struct platform_device_id s3c_rtc_driver_ids[] = {
{
.name = "s3c2410-rtc",
.driver_data = TYPE_S3C2410,
},{
.name = "s3c2416-rtc",
.driver_data = TYPE_S3C2416,
},{
.name = "s3c2443-rtc",
.driver_data = TYPE_S3C2443,
},{
.name = "s3c64xx-rtc",
.driver_data = TYPE_S3C64XX,
},
{}
};
在上面这个列表中,有s3c2410-rtc,因此RTC设备与驱动匹配上了。下面我们再来看看s3c_rtc_probe函数:
static int __devinit s3c_rtc_probe(struct platform_device *pdev)
{
structrtc_device *rtc;
structrtc_time rtc_tm;
structresource *res;
intret;
inttmp;
pr_debug("%s:probe=%p\n", __func__, pdev);
/*find the IRQs */
//得到RTC的时间节拍中断号
s3c_rtc_tickno = platform_get_irq(pdev,1);
if(s3c_rtc_tickno < 0) {
dev_err(&pdev->dev,"no irq for rtc tick\n");
return-ENOENT;
}
//得到RTC的报警中断号
s3c_rtc_alarmno = platform_get_irq(pdev,0);
if(s3c_rtc_alarmno < 0) {
dev_err(&pdev->dev, "no irqfor alarm\n");
return-ENOENT;
}
pr_debug("s3c2410_rtc: tick irq %d, alarm irq%d\n",
s3c_rtc_tickno,s3c_rtc_alarmno);
/*get the memory region */
//得到RTC的内存资源
res= platform_get_resource(pdev, IORESOURCE_MEM, 0);
if(res == NULL) {
dev_err(&pdev->dev,"failed to get memory region resource\n");
return-ENOENT;
}
//申请内存资源
s3c_rtc_mem =request_mem_region(res->start, resource_size(res),
pdev->name);
if(s3c_rtc_mem == NULL) {
dev_err(&pdev->dev,"failed to reserve memory region\n");
ret= -ENOENT;
gotoerr_nores;
}
//将内存重新映射
s3c_rtc_base = ioremap(res->start,resource_size(res));
if(s3c_rtc_base == NULL) {
dev_err(&pdev->dev,"failed ioremap()\n");
ret= -EINVAL;
gotoerr_nomap;
}
//得到RTC的时钟信号
rtc_clk= clk_get(&pdev->dev, "rtc");
if(IS_ERR(rtc_clk)) {
dev_err(&pdev->dev,"failed to find rtc clock source\n");
ret = PTR_ERR(rtc_clk);
rtc_clk = NULL;
goto err_clk;
}
//RTC时钟信号有效
clk_enable(rtc_clk);
/* check to seeif everything is setup correctly */
//使能RTC,并对RTCCON寄存器进行设置;如果该函数的第二个参数为0,则无效RTC
s3c_rtc_enable(pdev, 1);
pr_debug("s3c2410_rtc: RTCCON=%02x\n",
readw(s3c_rtc_base+ S3C2410_RTCCON));
//唤醒RTC设备
device_init_wakeup(&pdev->dev,1);
/*register RTC and exit */
//注册RTC类
rtc= rtc_device_register("s3c",&pdev->dev, &s3c_rtcops,
THIS_MODULE);
if(IS_ERR(rtc)) {
dev_err(&pdev->dev,"cannot attach rtc\n");
ret= PTR_ERR(rtc);
gotoerr_nortc;
}
//得到当前CPU的类型,因为该驱动是通用的,也适用于其他s3c类型的处理器
s3c_rtc_cpu_type = s3c_rtc_get_driver_data(pdev);
/*Check RTC Time */
//得到RTC的当前时间
s3c_rtc_gettime(NULL, &rtc_tm);
//如果RTC的当前时间无效,则重新设置
if(rtc_valid_tm(&rtc_tm)) {
rtc_tm.tm_year = 100;
rtc_tm.tm_mon = 0;
rtc_tm.tm_mday = 1;
rtc_tm.tm_hour = 0;
rtc_tm.tm_min = 0;
rtc_tm.tm_sec = 0;
//设置RTC当前时间
s3c_rtc_settime(NULL, &rtc_tm);
dev_warn(&pdev->dev,"warning: invalid RTC value so initializing it\n");
}
//依据CPU的类型,设置RTC节拍
if(s3c_rtc_cpu_type != TYPE_S3C2410)
rtc->max_user_freq= 32768;
else
rtc->max_user_freq= 128;
if(s3c_rtc_cpu_type == TYPE_S3C2416 || s3c_rtc_cpu_type == TYPE_S3C2443) {
tmp= readw(s3c_rtc_base + S3C2410_RTCCON);
tmp|= S3C2443_RTCCON_TICSEL;
writew(tmp,s3c_rtc_base + S3C2410_RTCCON);
}
//保存平台总线设备的私有数据,
platform_set_drvdata(pdev, rtc);
//设置TICNT寄存器
s3c_rtc_setfreq(&pdev->dev, 1);
//申请RTC报警中断
ret= request_irq(s3c_rtc_alarmno,s3c_rtc_alarmirq,
0, "s3c2410-rtcalarm", rtc);
if(ret) {
dev_err(&pdev->dev,"IRQ%d error %d\n", s3c_rtc_alarmno,ret);
gotoerr_alarm_irq;
}
//申请RTC时间节拍中断
ret= request_irq(s3c_rtc_tickno,s3c_rtc_tickirq,
0, "s3c2410-rtctick", rtc);
if(ret) {
dev_err(&pdev->dev,"IRQ%d error %d\n", s3c_rtc_tickno,ret);
free_irq(s3c_rtc_alarmno, rtc);
gotoerr_tick_irq;
}
//RTC时钟无效
clk_disable(rtc_clk);
return0;
err_tick_irq:
free_irq(s3c_rtc_alarmno, rtc);
err_alarm_irq:
platform_set_drvdata(pdev,NULL);
rtc_device_unregister(rtc);
err_nortc:
s3c_rtc_enable(pdev, 0);
clk_disable(rtc_clk);
clk_put(rtc_clk);
err_clk:
iounmap(s3c_rtc_base);
err_nomap:
release_resource(s3c_rtc_mem);
err_nores:
returnret;
}
下面介绍一下2440的RTC操作集——s3c_rtcops:
static const struct rtc_class_ops s3c_rtcops = {
.read_time = s3c_rtc_gettime, //读取当前时间
.set_time = s3c_rtc_settime, //设置当前时间
.read_alarm = s3c_rtc_getalarm, //读取报警时间
.set_alarm = s3c_rtc_setalarm, //设置报警时间
.proc = s3c_rtc_proc,
.alarm_irq_enable= s3c_rtc_setaie, //用于设置RTCALM寄存器
};
在上面介绍过的s3c_rtc_probe函数内,用到了rtc_device_register函数来注册RTC设备,该函数在drivers/rtc/Class.c文件内被定义。Class.c文件主要定义了RTC子系统。在该文件中,有:
subsys_initcall(rtc_init);
说明系统启动后会执行rtc_init函数:
static int __init rtc_init(void)
{
//创建RTC子类
rtc_class= class_create(THIS_MODULE, "rtc");
if(IS_ERR(rtc_class)) {
printk(KERN_ERR"%s: couldn't create class\n", __FILE__);
returnPTR_ERR(rtc_class);
}
rtc_class->suspend= rtc_suspend;
rtc_class->resume= rtc_resume;
//RTC设备初始化
rtc_dev_init();
rtc_sysfs_init(rtc_class);
return0;
}
上面函数中的rtc_dev_init函数是在drivers/rtc/Rtc-dev.c文件内定义的:
void __init rtc_dev_init(void)
{
interr;
//申请一个字符设备,RTC也是一个字符设备
err= alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
if(err < 0)
printk(KERN_ERR"%s: failed to allocate char dev region\n",
__FILE__);
}
通过上面分析可看出,系统启动后会自动申请RTC,而具体的注册该设备是靠前面提到的rtc_device_register函数来完成的。我们再来看看这个函数:
struct rtc_device*rtc_device_register(const char *name, struct device *dev,
conststruct rtc_class_ops *ops,
structmodule *owner)
{
structrtc_device *rtc;
structrtc_wkalrm alrm;
intid, err;
//得到一个新的ID
id= ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
if(id < 0) {
err= id;
gotoexit;
}
//为RTC设备分配一块内存,并清零
rtc= kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
if(rtc == NULL) {
err= -ENOMEM;
gotoexit_ida;
}
//为RTC设备赋值
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);
/* Init timerqueue */
//初始化定时器队列
timerqueue_init_head(&rtc->timerqueue);
//在rtc->irqwork队列中添加rtc_timer_do_work任务,也就是当程序出现schedule_work(&rtc->irqwork)这个语句中,实际是调用的rtc_timer_do_work函数
INIT_WORK(&rtc->irqwork,rtc_timer_do_work);
/*Init aie timer */
rtc_timer_init(&rtc->aie_timer,rtc_aie_update_irq, (void *)rtc);
/*Init uie timer */
rtc_timer_init(&rtc->uie_rtctimer,rtc_uie_update_irq, (void *)rtc);
/* Init pie timer */
hrtimer_init(&rtc->pie_timer,CLOCK_MONOTONIC, HRTIMER_MODE_REL);
rtc->pie_timer.function = rtc_pie_update_irq;
rtc->pie_enabled= 0;
/*Check to see if there is an ALARM already set in hw */
//检查是否硬件已发生了报警
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);
//注册RTC设备
err= device_register(&rtc->dev);
if(err) {
put_device(&rtc->dev);
gotoexit_kfree;
}
rtc_dev_add_device(rtc);
//在sysfs文件系统中添加RTC设备
rtc_sysfs_add_device(rtc);
//在proc文件系统中添加RTC设备
rtc_proc_add_device(rtc);
dev_info(dev,"rtc core: registered %s as %s\n",
rtc->name,dev_name(&rtc->dev));
returnrtc;
exit_kfree:
kfree(rtc);
exit_ida:
ida_simple_remove(&rtc_ida,id);
exit:
dev_err(dev,"rtc core: unable to register %s, err = %d\n",
name,err);
returnERR_PTR(err);
}
在上面的函数中用到了rtc_dev_prepare和rtc_dev_add_device函数,这两个函数都是在drivers/rtc/Rtc-dev.c文件内定义的:
void rtc_dev_prepare(struct rtc_device*rtc)
{
if(!rtc_devt)
return;
//RTC设备不能多于16个
if(rtc->id >= RTC_DEV_MAX) {
pr_debug("%s:too many RTC devices\n", rtc->name);
return;
}
rtc->dev.devt= MKDEV(MAJOR(rtc_devt), rtc->id);
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
INIT_WORK(&rtc->uie_task,rtc_uie_task);
setup_timer(&rtc->uie_timer,rtc_uie_timer, (unsigned long)rtc);
#endif
//初始化字符设备结构
cdev_init(&rtc->char_dev,&rtc_dev_fops);
rtc->char_dev.owner= rtc->owner;
}
voidrtc_dev_add_device(struct rtc_device *rtc)
{
//为系统添加RTC字符设备
if (cdev_add(&rtc->char_dev,rtc->dev.devt, 1))
printk(KERN_WARNING"%s: failed to add char device %d:%d\n",
rtc->name,MAJOR(rtc_devt), rtc->id);
else
pr_debug("%s:dev (%d:%d)\n", rtc->name,
MAJOR(rtc_devt),rtc->id);
}
在rtc_dev_prepare函数中提到了rtc_dev_fops,它就是RTC的操作集:
static const struct file_operationsrtc_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_dev_ioctl函数:
static long rtc_dev_ioctl(struct file*file,
unsignedint cmd, unsigned long arg)
{
interr = 0;
structrtc_device *rtc = file->private_data;
conststruct rtc_class_ops *ops = rtc->ops;
structrtc_time tm;
structrtc_wkalrm alarm;
void __user *uarg = (void __user*) arg;
err =mutex_lock_interruptible(&rtc->ops_lock);
if(err)
return err;
/*check that the calling task has appropriate permissions
* for certain ioctls. doing this check here isuseful
* to avoid duplicate code in each driver.
*/
//对有些命令先进行预处理,如果不符合要求,就提前退出
switch(cmd) {
caseRTC_EPOCH_SET:
caseRTC_SET_TIME:
if(!capable(CAP_SYS_TIME))
err= -EACCES;
break;
caseRTC_IRQP_SET:
if(arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
err= -EACCES;
break;
caseRTC_PIE_ON:
if(rtc->irq_freq > rtc->max_user_freq &&
!capable(CAP_SYS_RESOURCE))
err= -EACCES;
break;
}
if(err)
gotodone;
/*
* Drivers *SHOULD NOT* provide ioctlimplementations
* for these requests. Instead, provide methods to
* support the following code, so that theRTC's main
* features are accessible without usingioctls.
*
* RTC and alarm times will be in UTC, bypreference,
* but dual-booting with MS-Windows impliesRTCs must
* use the local wall clock time.
*/
switch(cmd) {
caseRTC_ALM_READ: //读报警时间
mutex_unlock(&rtc->ops_lock);
//读取报警时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_getalarm函数
err= rtc_read_alarm(rtc, &alarm);
if(err < 0)
returnerr;
if(copy_to_user(uarg, &alarm.time, sizeof(tm)))
err= -EFAULT;
returnerr;
caseRTC_ALM_SET: //设置报警时间
mutex_unlock(&rtc->ops_lock);
if(copy_from_user(&alarm.time, uarg, sizeof(tm)))
return-EFAULT;
alarm.enabled= 0;
alarm.pending= 0;
alarm.time.tm_wday= -1;
alarm.time.tm_yday= -1;
alarm.time.tm_isdst= -1;
/*RTC_ALM_SET alarms may be up to 24 hours in the future.
* Rather than expecting every RTC to implement"don't care"
* for day/month/year fields, just force thealarm to have
* the right values for those fields.
*
* RTC_WKALM_SET should be used instead. Not only does it
* eliminate the need for a separate RTC_AIE_ONcall, it
* doesn't have the "alarm 23:59:59 in the future" race.
*
* NOTE: some legacy code may have used invalid fields as
* wildcards, exposing hardware "periodicalarm" capabilities.
* Not supported here.
*/
{
unsignedlong now, then;
//读取当前时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_gettime函数
err= rtc_read_time(rtc, &tm);
if(err < 0)
returnerr;
//转换当前时间格式
rtc_tm_to_time(&tm,&now);
alarm.time.tm_mday= tm.tm_mday;
alarm.time.tm_mon = tm.tm_mon;
alarm.time.tm_year= tm.tm_year;
err = rtc_valid_tm(&alarm.time);
if(err < 0)
returnerr;
//转换报警时间格式
rtc_tm_to_time(&alarm.time,&then);
/*alarm may need to wrap into tomorrow */
//比较报警时间和当前时间,如果报警时间小于当前时间,则设置第二天的同一时间报警
if(then < now) {
rtc_time_to_tm(now+ 24 * 60 * 60, &tm);
alarm.time.tm_mday= tm.tm_mday;
alarm.time.tm_mon = tm.tm_mon;
alarm.time.tm_year = tm.tm_year;
}
}
//设置报警时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_setalarm函数
returnrtc_set_alarm(rtc, &alarm);
caseRTC_RD_TIME: //读取RTC时间
mutex_unlock(&rtc->ops_lock);
//读取当前时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_gettime函数
err= rtc_read_time(rtc, &tm);
if(err < 0)
returnerr;
if(copy_to_user(uarg, &tm, sizeof(tm)))
err= -EFAULT;
returnerr;
caseRTC_SET_TIME: //设置RTC时间
mutex_unlock(&rtc->ops_lock);
if(copy_from_user(&tm, uarg, sizeof(tm)))
return-EFAULT;
//设置RTC时间,最终调用的是Rtc-s3c.c文件中的s3c_rtc_settime函数
returnrtc_set_time(rtc, &tm);
caseRTC_PIE_ON:
err= rtc_irq_set_state(rtc, NULL, 1);
break;
caseRTC_PIE_OFF:
err= rtc_irq_set_state(rtc, NULL, 0);
break;
caseRTC_AIE_ON: //报警中断有效
mutex_unlock(&rtc->ops_lock);
//设置报警中断,最终调用的是Rtc-s3c.c文件中的s3c_rtc_setaie函数
returnrtc_alarm_irq_enable(rtc, 1);
caseRTC_AIE_OFF: //报警中断无效
mutex_unlock(&rtc->ops_lock);
returnrtc_alarm_irq_enable(rtc, 0);
caseRTC_UIE_ON:
mutex_unlock(&rtc->ops_lock);
returnrtc_update_irq_enable(rtc, 1);
caseRTC_UIE_OFF:
mutex_unlock(&rtc->ops_lock);
returnrtc_update_irq_enable(rtc, 0);
caseRTC_IRQP_SET:
err= rtc_irq_set_freq(rtc, NULL, arg);
break;
caseRTC_IRQP_READ:
err= put_user(rtc->irq_freq, (unsigned long __user *)uarg);
break;
#if 0
caseRTC_EPOCH_SET:
#ifndef rtc_epoch
/*
* There were no RTC clocks before 1900.
*/
if(arg < 1900) {
err= -EINVAL;
break;
}
rtc_epoch= arg;
err= 0;
#endif
break;
caseRTC_EPOCH_READ:
err= put_user(rtc_epoch, (unsigned long __user *)uarg);
break;
#endif
caseRTC_WKALM_SET:
mutex_unlock(&rtc->ops_lock);
if(copy_from_user(&alarm, uarg, sizeof(alarm)))
return-EFAULT;
returnrtc_set_alarm(rtc, &alarm);
caseRTC_WKALM_RD:
mutex_unlock(&rtc->ops_lock);
err= rtc_read_alarm(rtc, &alarm);
if(err < 0)
returnerr;
if(copy_to_user(uarg, &alarm, sizeof(alarm)))
err= -EFAULT;
returnerr;
default:
/*Finally try the driver's ioctl interface */
if(ops->ioctl) {
err= ops->ioctl(rtc->dev.parent, cmd, arg);
if(err == -ENOIOCTLCMD)
err= -ENOTTY;
}else
err= -ENOTTY;
break;
}
done:
mutex_unlock(&rtc->ops_lock);
returnerr;
}
驱动介绍完了,下面介绍应用。
系统的默认配置已经添加了RTC的部分,因此不用再修改,而且当系统启动后,会读取RTC中的时钟,以更新同步系统时间。
系统启动后,从打印出的信息来看,RTC已加载:
s3c-rtc s3c2410-rtc: rtc disabled, re-enabling
s3c-rtc s3c2410-rtc: rtc core: registered s3c as rtc0
s3c-rtc s3c2410-rtc: warning: invalid RTC value so initializingit
并且还有下面一句:
s3c-rtcs3c2410-rtc: setting systemclock to 2000-01-01 00:00:00 UTC (946684800)
说明系统已进行了时钟同步。
系统启动后,我们可以通过命令来查看系统的时间:
[root@zhaocj/]#date
SatJan 1 00:01:04 UTC 2000
下面我们就写一段应用程序来查看和修改RTC时间:
/**************
***mydate.c***
**************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
intmain(int argc, char **argv)
{
int fd, retval;
struct rtc_time rtc_tm;
fd = open("/dev/rtc0", O_RDONLY);
if (fd == -1) {
perror("/dev/rtc0");
exit(errno);
}
printf("\n\tRTC Driver Test Example.\n");
if(argc == 1)
goto test_READ;
if(argc !=7)
{
printf( "wrong!\n");
return 1;
}
//为时间变量赋值
//要把字符串转换成整型
//年和月比较特殊
rtc_tm.tm_year =atoi(argv[1])-1900;
rtc_tm.tm_mon=atoi(argv[2])-1;;
rtc_tm.tm_mday=atoi(argv[3]);
rtc_tm.tm_hour=atoi(argv[4]);
rtc_tm.tm_min=atoi(argv[5]);
rtc_tm.tm_sec=atoi(argv[6]);
retval = ioctl(fd, RTC_SET_TIME, &rtc_tm); //设置RTC时间
if (retval == -1) {
perror("RTC_RD_TIME ioctl");
exit(errno);
}
test_READ:
retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); //读取RTC时间
if (retval == -1) {
perror("RTC_RD_TIME ioctl");
exit(errno);
}
printf("\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
rtc_tm.tm_year + 1900, rtc_tm.tm_mon + 1,rtc_tm.tm_mday,
rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
done:
printf("\n\t *** Test complete ***\n");
close(fd);
return 0;
}
编译后下载到temp目录下,运行:
[root@zhaocj/temp]#./mydate
RTC Driver Test Example.
CurrentRTC date/time is 2000-1-1, 0:20:31.
*** Test complete ***
如果mydate没有带参数,表示只读取RTC时间。
[root@zhaocj/temp]#./mydate 2013 7 12 11 29 30
RTC Driver Test Example.
CurrentRTC date/time is 2013-7-12, 11:29:30.
*** Test complete ***
如果mydate带有表示年、月、日、时、分、秒的参数,则表示设置RTC时间。
下面我们再一段应用RTC报警中断的应用程序:
/***************
***myalm.c***
***************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
intmain(int argc, char **argv)
{
int fd, retval;
unsigned long data;
struct rtc_time rtc_tm;
fd = open("/dev/rtc0",O_RDONLY);
if (fd == -1) {
perror("/dev/rtc0");
exit(errno);
}
printf("\nt\tRTC Driver TestExample.\n");
retval = ioctl(fd, RTC_RD_TIME,&rtc_tm); //读取当前时间
if (retval == -1) {
perror("RTC_RD_TIMEioctl");
exit(errno);
}
printf("\nCurrent RTC date/time is%d-%d-%d, %02d:%02d:%02d.\n",
rtc_tm.tm_year + 1900,rtc_tm.tm_mon + 1,rtc_tm.tm_mday,
rtc_tm.tm_hour, rtc_tm.tm_min,rtc_tm.tm_sec);
rtc_tm.tm_sec += 5; // 设置5秒后报警
//时间溢出调整
if (rtc_tm.tm_sec >= 60) {
rtc_tm.tm_sec %= 60;
rtc_tm.tm_min++;
}
if (rtc_tm.tm_min == 60) {
rtc_tm.tm_min = 0;
rtc_tm.tm_hour++;
}
if (rtc_tm.tm_hour == 24)
rtc_tm.tm_hour= 0;
retval = ioctl(fd, RTC_ALM_SET,&rtc_tm); //设置RTC报警时间
if (retval == -1) {
if (errno == ENOTTY) {
fprintf(stderr,"\n...AlarmIRQs not supported.\n");
}
perror("RTC_ALM_SETioctl");
exit(errno);
}
retval = ioctl(fd, RTC_ALM_READ,&rtc_tm); //读取报警时间
if (retval == -1) {
perror("RTC_ALM_READioctl");
exit(errno);
}
fprintf(stderr, "Alarm time now setto %02d:%02d:%02d.\n",
rtc_tm.tm_hour, rtc_tm.tm_min,rtc_tm.tm_sec);
retval = ioctl(fd, RTC_AIE_ON, 0); //使能RTC报警中断
if (retval == -1) {
perror("RTC_AIE_ONioctl");
exit(errno);
}
fprintf(stderr, "Waiting 5 secondsfor alarm...");
/* This blocks until the alarm ring causes an interrupt */
retval = read(fd, &data,sizeof(unsigned long)); //等待RTC报警中断的发生
if (retval == -1) {
perror("read");
exit(errno);
}
fprintf(stderr, " okay. Alarmrang.\n");
retval = ioctl(fd, RTC_AIE_OFF, 0); //关闭RTC报警
if (retval == -1) {
perror("RTC_AIE_OFFioctl");
exit(errno);
}
printf("\n\t\t *** Test complete ***\n");
close(fd);
return 0;
}
[root@zhaocj/temp]#./myalm
RTC Driver Test Example.
CurrentRTC date/time is 2013-7-12, 12:48:23.
Alarmtime now set to 12:48:28.
Waiting5 seconds for alarm... okay. Alarm rang.
*** Test complete ***
由于系统的RTC报警中断只能是24小时内,因此不能设置RTC报警中断的年、月、日。