当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > linux下的rtc机制

linux下的rtc机制 时间:2014-10-18      来源:未知

Linux的RTC驱动相对还是比较简单的,可以将它作为一个普通的字符型设备,或者一个misc设备,也可以是一个平台设备,这都没有关系,主要还是对rtc_ops这个文件操作结构体中的成员填充,这里主要涉及到两个方面比较重要:

1. 在Linux中有硬件时钟与系统时钟等两种时钟。硬件时钟是指主机板上的时钟设备,也就是通常可在BIOS画面设定的时钟。系统时钟则是指kernel中的时钟。当Linux启动时,系统时钟会去读取硬件时钟的设定,之后系统时钟即独立运作。所有Linux相关指令与函数都是读取系统时钟的设定。

系统时钟的设定就是我们常用的date命令,而我们写的RTC驱动就是为硬件时钟服务的,它有属于自己的命令hwclock,因此使用date命令是不可能调用到我们的驱动的(在这点上开始把我郁闷到了,写完驱动之后,傻傻的用date指令来测试,当然结果是什么都没有),我们可以通过hwclock的一些指令来实现更新rtc时钟——也就是系统时钟和硬件时钟的交互。

hwclock –r显示硬件时钟与日期

hwclock –s将系统时钟调整为与目前的硬件时钟一致。

hwclock –w将硬件时钟调整为与目前的系统时钟一致。

用户输入 hwclck -s // 这个命令是 把硬件的时钟更新到系统中去

这个命令会调用busybox源码中的hwclock.c,在目录util-linux/hwclock.c 中的 ->int hwclock_main(int argc UNUSED_PARAM, char **argv)

后面的参数会以argv形式接收

opt = getopt32(argv, "lurswtf:", &rtcname);
        会把argv的参数进行转换 l -> 0x01
        u -> 0x02
        r -> 0x04
        s -> 0x08
        w -> 0x10
        t -> 0x20
        f -> 0x40 
        : -> 0x80
        #define HWCLOCK_OPT_LOCALTIME 0x01 
        #define HWCLOCK_OPT_UTC 0x02
        #define HWCLOCK_OPT_SHOW 0x04 // 等价 hwclock –r 显示硬件的时间
        #define HWCLOCK_OPT_HCTOSYS 0x08 // 等价 hwclock –s 硬件时间更新到系统时间
        #define HWCLOCK_OPT_SYSTOHC 0x10 // 等价 hwclock –w 系统时间更新到硬件时间 
        #define HWCLOCK_OPT_SYSTZ 0x20
        #define HWCLOCK_OPT_RTCFILE 0x40
         if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME)) // 判断是是否是 hwclock –l -u
         utc = (opt & HWCLOCK_OPT_UTC); 
         if (opt & HWCLOCK_OPT_HCTOSYS) // 判断是是否是 hwclock –s
        to_sys_clock(&rtcname, utc);
        else if (opt & HWCLOCK_OPT_SYSTOHC) // 判断是是否是 hwclock –w
        from_sys_clock(&rtcname, utc);
        else
        /* default HWCLOCK_OPT_SHOW */ // 默认是 hwclock –r 
        show_clock(&rtcname, utc);
        hwclock –s ->to_sys_clock-> read_rtc(pp_rtcname, NULL, utc); // 读rtc的时间
        -> fd = rtc_xopen(pp_rtcname, O_RDONLY)
        *default_rtc = "/dev/rtc";
        rtc = open(*default_rtc, flags);
        *default_rtc = "/dev/rtc0";
        rtc = open(*default_rtc, flags);
        *default_rtc = "/dev/misc/rtc";
        // 会打开这几个默认的文件
        -> rtc_read_tm(&tm_time, fd);
        -> xioctl(fd, RTC_RD_TIME, ptm);
        // 读系统的时间
        -> settimeofday(&tv, &tz)) // 设置系统的时间
        hwclock –w ->from_sys_clock(&rtcname, utc); -> rtc = rtc_xopen(pp_rtcname, O_WRONLY);
        *default_rtc = "/dev/rtc";
        rtc = open(*default_rtc, flags);
        *default_rtc = "/dev/rtc0";
        rtc = open(*default_rtc, flags);
        *default_rtc = "/dev/misc/rtc";
        // 会打开这几个默认的文件
        -> gettimeofday(&tv, NULL); // 获得系统时间
        -> xioctl(rtc, RTC_SET_TIME, &tm_time); // 设置系统时间
        -> close(rtc) // 
        hwclock –r -> show_clock(const char **pp_rtcname, int utc) 
        -> time_t t = read_rtc(pp_rtcname, &sys_tv, utc);
        ->*default_rtc = "/dev/rtc";
        rtc = open(*default_rtc, flags);
        *default_rtc = "/dev/rtc0";
        rtc = open(*default_rtc, flags);
        *default_rtc = "/dev/misc/rtc";
        // 会打开这几个默认的文件
        -> fd = rtc_xopen(pp_rtcname, O_RDONLY);
        -> rtc_read_tm(&tm_time, fd); 
        -> xioctl(fd, RTC_RD_TIME, ptm);

以上可以知道, 读时间使用ioctl进行的,使用两个命令

RTC_RD_TIME // 读时间
        RTC_SET_TIME // 设置时间

第二部分: rtc驱动架构分析

rtc的驱动架构是基于platform机制实现的,platform_device是由设备树生成

rtc的设备树如下:

rtc@10070000 
        {
                compatible = "samsung,s3c6410-rtc";
                reg = < 0x10070000 0x100>;
                interrupts = < 0 44 0>, <0 45 0>;
                clocks = < &clock 346>;
                clock-names = "rtc";
                status = "disabled";
        };

这个设备树会生成platform_device

驱动在driver /rtc/rtc-s3c.c 文件中定义

static struct platform_driver s3c_rtc_driver = {
        .probe = s3c_rtc_probe,
        .remove = s3c_rtc_remove,
        .id_table = s3c_rtc_driver_ids,
        .driver = {
        .name = "s3c-rtc",
        .owner = THIS_MODULE,
        .pm = &s3c_rtc_pm_ops,
        .of_match_table = of_match_ptr(s3c_rtc_dt_match),
        },
        };
        module_platform_driver(s3c_rtc_driver);

实现了platform_driver s3c_rtc_driver的注册

设备树中的compatible = "samsung,s3c6410-rtc";和驱动中的 .compatible = "samsung,s3c6410-rtc",名称一直时,会执行驱动的probe函数-> s3c_rtc_probe

在probe函数中注册一个字符设备驱动

rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops, 
        -> rtc = rtc_device_register(name, dev, ops, owner);
        -> of_id = of_alias_get_id(dev->of_node, "rtc"); // 注册一个rtc的类
        -> rtc_dev_prepare(rtc);
        -> cdev_init(&rtc->char_dev, &rtc_dev_fops);
        -> rtc_dev_add_device(rtc);
        -> if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
        -> rtc_sysfs_add_device(rtc); // 等价于 mknod /dev/rtc c 254 0
        -> s3c_rtc_gettime(NULL, &rtc_tm); // 获得系统的时间

以上是一个字符设备的创建。

注册了一个cdev结构体和file_operations结构体rtc_dev_fops

rtc_dev_fops实现如下:
        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,
        };

由以上可知 : 应用程序调用ioctl 驱动也调用ioctl

hwclock –w -> xioctl(fd, RTC_RD_TIME, ptm); -> rtc_dev_ioctl(命令) (用户空间) (内核空间)
        -> case RTC_RD_TIME:rtc_read_time(rtc, &tm);
        if (copy_to_user(uarg, &tm, sizeof(tm)))

由以上可知 : 应用程序调用ioctl 驱动也调用ioctl

hwclock –s -> xioctl(fd, RTC_SET_TIME, ptm); -> rtc_dev_ioctl(命令) (用户空间) (内核空间) 
        -> case RTC_SET_TIME: 
        if (copy_from_user(&tm, uarg, sizeof(tm)))
        return rtc_set_time(rtc, &tm);
        hwclock –r -> xioctl(fd, RTC_RD_TIME , ptm); -> rtc_dev_ioctl(命令) (用户空间) (内核空间) 
        -> case RTC_RD_TIME: rtc_read_time(rtc, &tm);
        if (copy_to_user(uarg, &tm, sizeof(tm)))

上一篇:Linux网络编程之套接字

下一篇:基于FS4412内核移植之USB驱动的移植

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技集团有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部