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. 格式转换工具:使用kgEncode转换压缩无损音乐

    在kugou安装目录下,有kgEncode目录,可以在各种格式中相互转换

  2. 「雕爷学编程」Arduino动手做(26)——4X4矩阵键盘模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  3. IDEA插件记录

    IDEA个性化设置 1. 开发工具 Free MyBatis plugin 作用:可以快速的在mybatis 的mapper 文件和xml文件中快速切换 Lombok 作用:为POJO类添加@Data ...

  4. flask之response

    import os from flask import Flask,render_template,redirect,jsonify,send_file app=Flask(__name__) #开发 ...

  5. 201771010128王玉兰《面向对象程序设计(Java)第十四周学习总结》

    第一部分:理论知识总结: (1)Swing 设计模式(Design pattern)是设计者一种流行的 思考设计问题的方法,是一套被反复使用,多数人 知晓的,经过分类编目的,代码设计经验的总结. 使用 ...

  6. airflow的安装和使用 - 完全版

    之前试用了azkaban一小段时间,虽然上手快速方便,但是功能还是太简单,不够灵活. Airflow使用代码来管理任务,这样应该是最灵活的,决定试一下. 我是python零基础,在使用airflow的 ...

  7. 远程快速安装redis和远程连接

    一.安装redis    1.设置redis的仓库地址, 执行命令: yum install epel-release    出现下图即设置成功 2.安装redis 执行命令如下: yum insta ...

  8. UPD链接实现稳健传输案例

    使用的类    DatagramSocket  用于发送数据和接收数据    此类的构造方法:        DatagramSocket();        DatagramSocket(端口号); ...

  9. SEPC:使用3D卷积从FPN中提取尺度不变特征,涨点神器 | CVPR 2020

    论文提出PConv为对特征金字塔进行3D卷积,配合特定的iBN进行正则化,能够有效地融合尺度间的内在关系,另外,论文提出SEPC,使用可变形卷积来适应实际特征间对应的不规律性,保持尺度均衡.PConv ...

  10. Kubectl exec 的工作原理解读

    对于经常和 Kubernetes 打交道的 YAML 工程师来说,最常用的命令就是 kubectl exec 了,通过它可以直接在容器内执行命令来调试应用程序.如果你不满足于只是用用而已,想了解 ku ...