Linux RTC设备驱动
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设备驱动的更多相关文章
- RTC设备驱动
问题:pcf8563 RTC设备驱动不能被正常的加载!问题分析过程. 问题在下午得到解决,虽然解决的办法比较笨,采用的是不断的使用printk来跟踪rtc-8563驱动的加载的过程,以及iic模块的工 ...
- 【Linux-驱动】RTC设备驱动架构
在Linux操作系统中,RTC设备驱动的架构如下图所示: RTC设备驱动涉及的文件:class.c.rtc-dev.c : 建立/dev/rtc0设备,同时注册相应的操作函数.interface.c ...
- linux块设备驱动之实例
1.注册:向内核注册个块设备驱动,其实就是用主设备号告诉内核这个代表块设备驱动 sbull_major = register_blkdev(sbull_major, "sbull&quo ...
- Linux 视频设备驱动V4L2最常用的控制命令
http://blog.csdn.net/shaolyh/article/details/6583226 Linux 视频设备驱动V4L2最常用的控制命令使用说明(1.02) 命令 功能 VIDIOC ...
- 深入理解Linux字符设备驱动
文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...
- Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】
本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...
- Smart210学习记录----beep linux字符设备驱动
今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...
- Linux块设备驱动详解
<机械硬盘> a:磁盘结构 -----传统的机械硬盘一般为3.5英寸硬盘,并由多个圆形蝶片组成,每个蝶片拥有独立的机械臂和磁头,每个堞片的圆形平面被划分了不同的同心圆,每一个同心圆称为一个 ...
- linux lcd设备驱动剖析四
在"linux lcd设备驱动剖析二"文章中,我们详细分析了s3c24xxfb_probe函数. 文章链接:http://blog.csdn.net/lwj103862095/ar ...
随机推荐
- 00005-js 获取uuid
admin.guid = function () { function S4() { return (((1+Math.random())*0x10000)|0).toString(16).subst ...
- node的events模块
events可以说是node实现异步的基石,也是其他几个常用核心模块api的异步方法的原型. var eventEmitter=require('events').EventEmitter; //va ...
- Java基础之数据类型
一.数据类型 基本数据类型介绍 byte 1字节 char 2字节 short 2字节 int 4字节 long 8字节 float 4字节 double 8字节 以上有Java中八大基本类型的7种, ...
- 解惑求助-关于NetCore2.2中间件响应的问题
背景介绍:基于netcore2.2开发api接口程序,自定义了一个异常捕获中间件,用于捕获未经处理的异常以及状态码404.500等访问(设计的出发点就是,出现了非200的响应,我这边全部会进行处理成2 ...
- Asp.net MVC验证那些事(1)-- 介绍和验证规则使用----[转]--[并修改了部分内容]
Asp.net MVC验证那些事(1)-- 介绍和验证规则使用 -----原文地址链接 数据的有效性验证,是程序开发中必不可少的环节.这篇文章,我们将用一个实例来说明如何在MVC中使用Validati ...
- stm32实现DMX512协议发送与接收(非标)
最近把玩了一下485,期间也接触了dmx512通信协议,该协议主要用于各种舞台灯光的控制当中,进而实现各种光效以及色彩变化.根据标准的512协议,其物理连接与传统上的RS485是完全一致的,并没有什么 ...
- 一个导致JVM物理内存消耗大的Bug
概述 最近我们公司在帮一个客户查一个JVM的问题(JDK1.8.0_191-b12),发现一个系统老是被OS Kill掉,是内存泄露导致的.在查的过程中,阴差阳错地发现了JVM另外的一个Bug.这个B ...
- 【网络安全】【02】Windows系统如何屏蔽自动更新
一.win键 + r ==> 输入 services.msc 二. win键 + r ==> 输入 gpedit.msc PS:我的电脑基本两年没有更新过了 -_-
- Centos慢慢长大(一)
1.写在前面 这将是一个系列性的文章.可能更多的是记录我在学习的过程中的一些感悟吧.我想强调的是在这一系列文章里我会从最小化的安装开始,然后逐渐的增加需要安装的软件.就象一个婴儿的诞生,慢慢的学走路. ...
- 你以为只有马云会灌鸡汤?Linux 命令行也会!
你以为只有马云会灌鸡汤?Linux 命令行也会! "Linux 太南了o(╥﹏╥)o","我累了不想奋斗了o(︶︿︶)o"... 不知道你有没有想过,在你快丧失 ...