array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 Linux驱动开发15之RTC驱动模型 - 爱码网

1.需要的文件有哪些

driver/rtc/class.c:         此文件向linux内核驱动模型注册了一个类RTC,同时为底层的RTC驱动提供了注册/注销RTC接口。同时实现了RTC相关的PM操作。

driver/rtc/rtc-dev.c:      将各种各样的RTC设备抽象成一个字符设备,同时提供文件操作函数集。

driver/rtc/rtc-sysfs.c:    用户可以通过sysfs文件系统方便快捷的操作rtc设备。

driver/rtc/rtc-proc.c:     可以通过proc文件系统获得rtc的相关信息,比如rtc_time, rtc_data等信息。

driver/rtc/interface.c:    提供应用程序和驱动的接口函数,主要是为rtc提供相关的调用接口。

driver/rtc/rtc-lib.c:         提供了一个rtcdata以及time之间的转换函数

driver/rtc/hctosys.c:     用于开机启动的时候获取rtc的值。

driver/rtc/rtc-xxx.c:       各式各样的rtc驱动。

2.RTC的设备在哪里注册的?

arch/arm/mach-s5pv210/mach-x210.c中。在initdata段加上的rtc

Linux驱动开发15之RTC驱动模型

Linux驱动开发15之RTC驱动模型

我们可以看出,名字被改了!但被改掉了!initdata是个数组,在哪里使用呢?

 

Linux驱动开发15之RTC驱动模型

//注意:是platform_add_devices是通过for循环调用platform_devices_add()函数
//通过这个函数就把这个数组里边所有的设备资源都注册到了platform设备总线下

根据宏的展开:
MACHINE_START(SMDKC110, "SMDKC110")
......
.init_machine = smdkc110_machine_init,,  //
这个函数是被放在“.arch.info.init”段,在加载内核时会被自动调用
......
MACHINE_END

好了,上述就是设备的注册!

3.RTC的驱动注册在哪里?

Drivers/rtc/rtc-smdkc110.c

00482: static int __init smdkc110_rtc_init(void)
00483: {
00484: printk(banner);
00485: return platform_driver_register(&smdkc110_rtc_driver);
00486: }

下面看下smdkc110_rtc_driver这个结构体。

00468: static struct platform_driver smdkc110_rtc_driver = {
00469: .probe = smdkc110_rtc_probe,
00470: .remove = __devexit_p(smdkc110_rtc_remove),
00471: .suspend = smdkc110_rtc_suspend,
00472: .resume = smdkc110_rtc_resume,
00473: .driver = {
00474:           .name = "smdkc110-rtc",
00475:           .owner = THIS_MODULE,
00476:           },
00477: };

那么系统启动时候,smdkc110_rtc_driver.driver.name = s5p_device_rtc.name此时驱动和设备匹配了!,然后执行probe函数!

00275: static const struct rtc_class_ops smdkc110_rtcops = {
00276: .read_time = smdkc110_rtc_gettime,
00277: .set_time = smdkc110_rtc_settime,
00278: .read_alarm = smdkc110_rtc_getalarm,
00279: .set_alarm = smdkc110_rtc_setalarm,
00280: };

00471: static const struct file_operations rtc_dev_fops = {
00472: .owner = THIS_MODULE,
00473: .llseek = no_llseek,
00474: .read = rtc_dev_read,       //读方法
00475: .poll = rtc_dev_poll, //轮询
00476: .unlocked_ioctl = rtc_dev_ioctl,      //IO控制
00477: .open = rtc_dev_open,     //打开
00478: .release = rtc_dev_release,       //释放
00479: .fasync = rtc_dev_fasync, //异步通知
00480: };

00159: struct rtc_device{
00161: struct device dev;
00162: struct module *owner;
00164: int id;
00165: char name[RTC_DEVICE_NAME_SIZE];
00167: const struct rtc_class_ops *ops;
00168: struct mutex ops_lock;
00170: struct cdev char_dev;
00171: unsigned long flags;
00173: unsigned long irq_data;
00174: spinlock_t irq_lock;
00175: wait_queue_head_t irq_queue;
00176: struct fasync_struct *async_queue;
00178: struct rtc_task *irq_task;
00179: spinlock_t irq_task_lock;
00180: int irq_freq;
00181: int max_user_freq;
00182: } ? end rtc_device ? ;

Linux驱动开发15之RTC驱动模型

 

 

到此完成了设备驱动的注册,在目录下建立:/dev/rtc0/sys/class/rtc/rtc0/proc/driver/rtc/sys/bus/platform/drivers/smdkc110-rtc/smdkc110-rtc/rtc/rtc0,建立这四个东西。

4.这些结构体的作用?到底是什么关系?

static const struct rtc_class_ops smdkc110_rtcops

static const struct file_operations rtc_dev_fops

struct rtc_device *rtc

首先我们要知道的,对于目前platform平台总线的注册,必须要注册三个东西:

  1. RtcPlatform平台总线的注册,包括设备和驱动;
  2. device设备注册出现设备号,应用层通过file_operations结构体中的函数操控硬件,这是操控硬件第一种方法;
  3. class属性文件注册,通过/sys/class中的接口直接对硬件进行操控,这是操控硬件第二种方法;

这样说来,有很多个结构体,分别对应file_operations结构体、class结构体、硬件相关的device结构体等等。比较乱,而且不好操作,不好找。那么这就发明了针对不同的硬件包含了所有结构体信息的一个东西,叫做rtc_device结构体,我们来看下:

00159: struct rtc_device{
00161: struct device dev;
00162: struct module *owner;
00164: int id;
00165: char name[RTC_DEVICE_NAME_SIZE];
00167: const struct rtc_class_ops *ops;
00168: struct mutex ops_lock;
00170: struct cdev char_dev;
00171: unsigned long flags;
00173: unsigned long irq_data;
00174: spinlock_t irq_lock;
00175: wait_queue_head_t irq_queue;
00176: struct fasync_struct *async_queue;
00178: struct rtc_task *irq_task;
00179: spinlock_t irq_task_lock;
00180: int irq_freq;
00181: int max_user_freq;
00182: } ? end rtc_device ? ;

我们看到这个结构体中,既包含了struct device devchar name[RTC_DEVICE_NAME_SIZE];const struct rtc_class_ops *ops;struct cdev char_dev(file_operations);等等都包含了,也就是说通过这个结构体,我们可以完成所有注册,也可以完成所有的硬件操作。

5.cdev_init/cdev_adddevice_add是什么关系?

首先我们来看下这个,感觉有点疑惑!为什么中间有一个device_add

 

Linux 内核中使用 struct cdev 结构来描述字符设备,我们在驱动程序中必须将已分配到的设备号以及设备操作接口(即为 struct file_operations 结构)赋予 struct cdev 结构变量。1)首先使用 cdev_alloc()函数向系统申请分配 struct cdev 结构, 2)再用cdev_init()函数初始化已分配到的结构并与 file_operations 结构关联起来。3)最后调用 cdev_add()函数将设备号与 struct  cdev 结构进行关联并向内核正式报告新的字符设备的注册,这样新设备可以被用起来了。

也就是说cdev_initcdev_add完成了字符设备的注册,我们加上其中包括前面的主次设备号的分配。但是这个时候并没有创建设备节点!!!!也就是说/dev下还没有此设备节点。我们创建设备节点的函数为:device_create。那么我们来看下这个设备节点怎么创建的!

device_create
    |
   + -- kzalloc struct device
    |
   +---device_register
                |
               +-----device_initialize
                |
               +-----device_add

device_createdevice_add多做的事情非常清楚了:
1. 新建struct device device_add是不会新建的,只会加。
2. 进行了初始化, 如果不调device_register 就得自己去调用device_initiali初始化。

关于正真设备文件的创建(不是指sys下的文件), 最终是由device_add函数里头的kobject_uevent(&dev->kobj, KOBJ_ADD)完成的调用的。

那么我们清楚了,

cdev_init、cdev_add完成设备的注册,device_add完成设备节点创建!

6RTC结构的框图

Linux驱动开发15之RTC驱动模型

Linux驱动开发15之RTC驱动模型

7.RTC驱动的读写

App:                  open(“/dev/rtc0”)

----------------------------------------------------------------------

Kernel:             sys_open

                            rtc_dev_fops.open

rtc_dev_open

                                              //根据次设备号找到以前用“rtc_device_register”注册的rtc_device

                                              struct rtc_device *rtc = container_of(inode->i_cdev, struct rtc_device, char_dev);

                                              const struct rtc_class_ops *ops = rtc->ops;

                                              err = ops->open ? ops->open(rtc->dev.parent) : 0;

                                              class结构体中没有open函数,因此不执行!

App:               ioctl(fd, RTC_ED_TIME,….)

--------------------------------------------------------------------------------

Kernel: sys_ioctl

                            rtc_dev_fops.ioctl

rtc_dev_ioctl

struct rtc_device *rtc = file->private_data;

                                              err = rtc_read_time(rtc, &tm);

                                                        err = rtc->ops->read_time(rtc->dev.parent, tm);

                                                                 smdkc110_rtc_gettime

相关文章: