您的位置:首页 > 运维架构 > Linux

基于S3C2440的Linux-3.6.6移植——实时时钟RTC

2014-10-11 11:57 393 查看
在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<stdio.h>

#include<linux/rtc.h>

#include<sys/ioctl.h>

#include<sys/time.h>

#include<sys/types.h>

#include<fcntl.h>

#include<unistd.h>

#include<stdlib.h>

#include<errno.h>



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<stdio.h>

#include<linux/rtc.h>

#include<sys/ioctl.h>

#include<sys/time.h>

#include<sys/types.h>

#include<fcntl.h>

#include<unistd.h>

#include<stdlib.h>

#include<errno.h>



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报警中断的年、月、日。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: