1. 在Linux2.6.29内核中,RTC是以平台设备的方式注册进内核的。

① RTC驱动定义于文件:drivers/rtc/rtc-s3c.c

static struct platform_driver s3c2410_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = __devexit_p(s3c_rtc_remove),
.suspend = s3c_rtc_suspend,
.resume = s3c_rtc_resume,
.driver = {
.name = "s3c2410-rtc",
.owner = THIS_MODULE,
},
};

② RTC平台资源定义于:arch/arm/plat-s3c24xx/devs.c

static struct resource s3c_rtc_resource[] = {
[] = {
.start = S3C24XX_PA_RTC,
.end = S3C24XX_PA_RTC + 0xff,
.flags = IORESOURCE_MEM,
},
[] = {
.start = IRQ_RTC,
.end = IRQ_RTC,
.flags = IORESOURCE_IRQ,
},
[] = {
.start = IRQ_TICK,
.end = IRQ_TICK,
.flags = IORESOURCE_IRQ
}
}; struct platform_device s3c_device_rtc = {
.name = "s3c2410-rtc",
.id = -,
.num_resources = ARRAY_SIZE(s3c_rtc_resource),
.resource = s3c_rtc_resource,
};

③ 当RTC设备驱动匹配到名字为“s3c2410-rtc”的设备时,会调用probe函数s3c_rtc_probe()

static int __devinit s3c_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
int ret;/* find the IRQs */
s3c_rtc_tickno = platform_get_irq(pdev, );
s3c_rtc_alarmno = platform_get_irq(pdev, );
/* get the memory region */
s3c_rtc_mem = request_mem_region(res->start,
res->end-res->start+,
pdev->name); s3c_rtc_base = ioremap(res->start, res->end - res->start + );/* check to see if everything is setup correctly */

s3c_rtc_enable(pdev, );
s3c_rtc_setfreq(&pdev->dev, );
device_init_wakeup(&pdev->dev, ); /* register RTC and exit */
rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
THIS_MODULE); rtc->max_user_freq = ; platform_set_drvdata(pdev, rtc);
return ;

(1) s3c_rtc_probe()函数分析1: 获取平台资源(中断号和IO内存),然后记录中断号,进行IO内存映射。

(2) s3c_rtc_probe()函数分析2: 调用rtc_device_register()函数,分配RTC的设备描述结构rtc_device,并填充其成员,然后进行设备注册(注册字符设备,注册进proc系统,注册进sys系统)

(3) s3c_rtc_probe()函数分析3: 保存RTC设备描述结构到平台设备驱动的dev域。

注: RTC的设备描述结构rtc_device是device结构的扩展,描述一个具体的RTC设备。

⑤ rtc_device_register()函数分析:

struct rtc_device *rtc_device_register(const char *name, struct device *dev,
const struct rtc_class_ops *ops,
struct module *owner)
{
struct rtc_device *rtc;
int id, err; if (idr_pre_get(&rtc_idr, GFP_KERNEL) == ) {
err = -ENOMEM;
goto exit;
} mutex_lock(&idr_lock);
err = idr_get_new(&rtc_idr, NULL, &id);
mutex_unlock(&idr_lock); if (err < )
goto exit; id = id & MAX_ID_MASK; rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
if (rtc == NULL) {
err = -ENOMEM;
goto exit_idr;
} rtc->id = id;
rtc->ops = ops;
rtc->owner = owner;
rtc->max_user_freq = ;
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); strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
dev_set_name(&rtc->dev, "rtc%d", id); rtc_dev_prepare(rtc); err = device_register(&rtc->dev);
if (err)
goto exit_kfree; rtc_dev_add_device(rtc);
rtc_sysfs_add_device(rtc);
rtc_proc_add_device(rtc); dev_info(dev, "rtc core: registered %s as %s\n",
rtc->name, dev_name(&rtc->dev)); return rtc; }

(1) 为RTC设备描述结构(rtc_device)分配空间,并填充相关成员。

(2) 通过rtc_dev_prepare()函数填充RTC字符设备的主设备号和操作函数集rtc_dev_fops

void rtc_dev_prepare(struct rtc_device *rtc)
{
rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); cdev_init(&rtc->char_dev, &rtc_dev_fops);
rtc->char_dev.owner = rtc->owner;
}

(3)通过rtc_dev_add_device()将RTC以字符设备注册进内核

void rtc_dev_add_device(struct rtc_device *rtc)
{
if (cdev_add(&rtc->char_dev, rtc->dev.devt, ))
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);
}

(4)RTC字符设备操作函数集rtc_dev_fops:用于实现访问RTC设备文件/dev/rtc0的操作方法,包括open、read、ioctl等方法。

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,
};

(5)RTC设备操作函数集s3c_rtcops:用于实现操作RTC设备的基本方法。也是rtc_device_register()函数中赋值给rtc(rtc_device结构)的ops成员的

static const struct rtc_class_ops s3c_rtcops = {
.open = s3c_rtc_open,
.release = s3c_rtc_release,
.read_time = s3c_rtc_gettime,
.set_time = s3c_rtc_settime,
.read_alarm = s3c_rtc_getalarm,
.set_alarm = s3c_rtc_setalarm,
.irq_set_freq = s3c_rtc_setfreq,
.irq_set_state = s3c_rtc_setpie,
.proc = s3c_rtc_proc,
};

注:s3c_rtcops属于RTC的设备描述结构rtc_device的成员,用于实现操作RTC的基本方法;而rtc_dev_fops属于cdev结构的成员,用于实现访问RTC设备文件/dev/rtc0的基本方法。rtc_dev_fops中的成员需要调用s3c_rtcops中的成员来实现其具体功能。

2. Linux2.6.29内核中,RTC平台驱动已经注册进内核,但RTC平台资源并未注册。我们添加RTC仅需要把RTC的平台资源结构体添加到平台资源初始化列表中即可。

(1)向smdk2440_devices[]数组中添加s3c_device_rtc

static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&smdk2440_device_eth,
&s3c_device_rtc,
};

(2)重新配置内核,加入RTC的驱动:Device Drivers--->Real Time Clock-->Samsung S3C series Soc RTC

3. RTC测试

(1)操作设备文件/dev/rtc0

(2)通过proc查看:cat /proc/driver/rtc

(3)通过sys文件系统接口:cat /sys/class/trc/rtc0/date; cat /sys/class/trc/rtc0/time

#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> static const char default_rtc[] = "/dev/rtc0"; int main(int argc, char** argv)
{
int fd, retval;
struct rtc_time rtc_tm;
const char* rtc = default_rtc; switch(argc)
{
case :
rtc = argv[];
break;
case :
break;
default:
fprintf(stderr, "usage: TestRtc [RtcDev]");
return ;
} fd = open(rtc, O_RDONLY);
if(fd == -)
{
perror(rtc);
exit(errno);
} retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
if(retval == -)
{
perror("RTC_RD_TIME ioctl");
exit(errno);
} printf("Current RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
rtc_tm.tm_year + , rtc_tm.tm_mon + , rtc_tm.tm_mday,
rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); return ;
}

Linux RTC设备驱动的更多相关文章

  1. RTC设备驱动

    问题:pcf8563 RTC设备驱动不能被正常的加载!问题分析过程. 问题在下午得到解决,虽然解决的办法比较笨,采用的是不断的使用printk来跟踪rtc-8563驱动的加载的过程,以及iic模块的工 ...

  2. 【Linux-驱动】RTC设备驱动架构

    在Linux操作系统中,RTC设备驱动的架构如下图所示: RTC设备驱动涉及的文件:class.c.rtc-dev.c : 建立/dev/rtc0设备,同时注册相应的操作函数.interface.c ...

  3. linux块设备驱动之实例

    1.注册:向内核注册个块设备驱动,其实就是用主设备号告诉内核这个代表块设备驱动 sbull_major  =  register_blkdev(sbull_major, "sbull&quo ...

  4. Linux 视频设备驱动V4L2最常用的控制命令

    http://blog.csdn.net/shaolyh/article/details/6583226 Linux 视频设备驱动V4L2最常用的控制命令使用说明(1.02) 命令 功能 VIDIOC ...

  5. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  6. Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】

    本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...

  7. Smart210学习记录----beep linux字符设备驱动

    今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...

  8. Linux块设备驱动详解

    <机械硬盘> a:磁盘结构 -----传统的机械硬盘一般为3.5英寸硬盘,并由多个圆形蝶片组成,每个蝶片拥有独立的机械臂和磁头,每个堞片的圆形平面被划分了不同的同心圆,每一个同心圆称为一个 ...

  9. linux lcd设备驱动剖析四

    在"linux lcd设备驱动剖析二"文章中,我们详细分析了s3c24xxfb_probe函数. 文章链接:http://blog.csdn.net/lwj103862095/ar ...

随机推荐

  1. 搞懂:前端跨域问题JS解决跨域问题VUE代理解决跨域问题原理

    什么是跨域 跨域:一个域下的文档或脚本试图去请求另一个域下的资源 广义的跨域包含一下内容: 1.资源跳转(链接跳转,重定向跳转,表单提交) 2.资源请求(内部的引用,脚本script,图片img,fr ...

  2. .net core 3.1 使用nlog记录日志 NLog.Web.AspNetCore

    背景 .net core 中已经集成了log的方法, 但是只能控制台输出不能写入文件等等. 常见第三方的的日志工具包括log4net, nlog等等, 本文介绍nlog 一. 引用程序集, nuget ...

  3. linux常用命令---网络端口信息与进程管理

    进程管理 进程管理

  4. DPDK 无锁队列Ring Library原理(学习笔记)

    参考自DPDK官方文档原文:http://doc.dpdk.org/guides-20.02/prog_guide/ring_lib.html 针对自己的理解做了一些辅助解释. 1 前置知识 1.1 ...

  5. 洛谷 p1605 迷宫问题 详解

    题解:dfs搜索 #include <iostream> #include <algorithm> #include <cstring> #include < ...

  6. Oracle操作时间-----摘抄而来

    1.日期时间间隔操作  当前时间减去7分钟的时间  select sysdate,sysdate - interval ’7’ MINUTE from dual  当前时间减去7小时的时间  sele ...

  7. 代码行数统计的Java和Python实现

    通过编写程序来统计文件的行数,可以在巩固文件IO知识的同时计算出自己的代码量,以下分别提供Java和Python实现的版本. 解决思路 两种版本的思路几乎相同,每一个文件夹(目录)内的行数都是其所有子 ...

  8. Spring Boot 教程(2) - Mybatis

    Spring Boot 教程 - Mybatis 1. 什么是Mybatis? MyBatis 是一款优秀的持久层框架,它支持自定义 SQL.存储过程以及高级映射.MyBatis 免除了几乎所有的 J ...

  9. yum CentOS7安装mysql

    配置阿里云yum源 [root@bogon ~]# cd /etc/yum.repos.d/ [root@bogon yum.repos.d]# mkdir repo_bak [root@bogon ...

  10. spring的动态代理实现

    Host.java package cn.zys.dynamiproxy; public class Host implements Rent{ public void rent(){ System. ...