LINUX设备驱动模型底层架构及组织方式

原创 2016-11-07 11:02:58 521
摘要:1、什么是设备驱动模型?设备驱动模型,说实话这个概念真的不好解释,他是一个比较抽象的概念,我在网上也是没有找到关于设备驱动模型的一个定义,那么今天就我所学、所了解到的,我对设备驱动模型的一个理解:设备驱动模型其实是Linux内核为了管理硬件上的设备和对应的驱动制定的一套软件体系。那么其实设备驱动模型是一个比较抽象、比较广的一个概念,一两句话是很难说清楚的,类(class)、总线(bus)、设备(d

1、什么是设备驱动模型?

设备驱动模型,说实话这个概念真的不好解释,他是一个比较抽象的概念,我在网上也是没有找到关于设备驱动模型的一个定义,那么今天就我所学、所了解

到的,我对设备驱动模型的一个理解:设备驱动模型其实是Linux内核为了管理硬件上的设备和对应的驱动制定的一套软件体系。那么其实设备驱动模型是一个比较

抽象、比较广的一个概念,一两句话是很难说清楚的,类(class)、总线(bus)、设备(device)、驱动(driver)、mdev(自动创建设备节点和设备类)

sysfs等都属于设备驱动模型的范畴。

2、为什么需要有设备驱动模型?

早期内核(2.4之前)没有的设备驱动模型的概念,但照样可以用;而到了2.6版本正式引入了设备驱动模型,因为实际的硬件设备越来越多,很多设备都有功耗要求等的

一些新特点,这就导致内核必须有一套更加优秀、更加易用的驱动体系来对设备进行分工管理,这就引入了我们这里所说的设备驱动模型。

设备驱动模型负责统一实现和维护一些特性,诸如:电源管理、热插拔、对象生命周期、用户空间和驱动空间的交互等基础设施(sysfs),设备驱动模型目的是简化驱动

程序编写、管理设备和驱动,但是客观上设备驱动模型本身设计和实现很复杂。其实这也就印证了一句话:越好用的东西,其实实现起来就越复杂。

3、设备驱动模型的底层架构

(1)kobject结构体

kobject结构体是设备驱动模型底层的一个结构体,这个结构体是设备驱动模型下的所有对象的一个基本单元,他是对设备驱动模型下所有对象抽象出来的共有的部分;

kobject结构体提供了一些公共型的服务:对象引用计数、维护对象链表、对象上锁、对用户空间的表示。

设备驱动模型中的各种对象其内部都会包含一个kobject,地位相当于面向对象思想中的总基类。

(2)kobject结构体元素分析

41.png


(3)kset结构体元素分析

42.png


从kset结构体可以看出来,kobject其实是被kset包含了,kset的主要作用是做顶层kobject的容器类,kset的主要目的是将各个kobject

(代表着各个对象)组织出目录层次架构,可以认为kset就是为了在sysfs中弄出目录,从而让设备驱动模型中的多个对象能够有层次有逻辑性的组织在一起。

(4)kset和kobject之间的关系

kset与kobject的关系:kset是kobject的一个容器,可以认为kset是一个目录,而kobject是这个目录下的各个文件,如果这个kset目录下还有子目录,那么这个

目录下就会存在子kset。

43.jpg

415.png




kset与kobject、kobject与kobject、kset与kset之间的连接关系:


     (1)平行关系下的连接关系:用kobject对象A、kset对象B进行说明

               (1)kobject与kobject的连接关系:A通过list_head结构体中的next指针指向下一个kobject对象的list_head结构体(如果A是一个链表尾,则next

                   指向他上层的kset对象中的list_head结构体),通过list_head结构体中的prev指针指向上一个kobject对象的list_head结构体(如果A是一个链

                   表头,则prev指向他上层的kset对象中的list_head结构体)。

               (2)kset与kobject的连接关系:B通过嵌入内部的kobject结构体中的list_head结构体中的next指针指向下一个kobject对象的list_head结构体(如果

                   B是一个链表尾,则next指向他的上层的kset对象中的list_head结构体),通过list_head结构体中的prev指针指向上一个kobject对象的list_head

                   结构体(如果B是一个链表头,则prev指向他上层的kset对象中的list_head结构体)。

               (3)kset与kset之间的连接关系:B通过嵌入内部的kobject结构体中的list_head结构体中的next指针指向下一个kset对象中的kobject结构体中的list_head

                   结构体(如果B是一个链表尾,则next指向他的上层的kset对象中的list_head结构体),通过list_head结构体中的prev指针指向上一个kset对象中的

                   kobject结构体中的list_head结构体(如果B是一个链表头,则prev指向他上层的kset对象中的list_head结构体)。

                     所以从上面可以看出来,平行关系的连接是通过kobject下的list_head结构体进行连接的,父类kset是通过kset下的list_head连接他下面的所有对象组成的链表头和链表尾。

                 (4)上下级关系下的连接关系:属于kset对象下的所有kobject对象通过parent指针指向父类kset中的kobject结构体,通过kset指针指向父类kset。

                  属于kset对象下的所有kset对象通过他下面的kobject结构体中parent指针指向父类kset中的kobject结构体,通过kobject结构体中的kset指针指向父类kset。

(5)kobj_type结构体

很多书中简称为ktype,每一个kobject都需要绑定一个ktype来提供相应功能

关键点1:sysfs_ops,提供该对象在sysfs中的操作方法(show和store)
关键点2:attribute,提供在sysfs中以文件形式存在的属性,其实就是应用接口

45.png



416.png

(6)kset、kobject、kobj_type3者之间的关系


 46.jpg

4、设备驱动模型下的总线式设备驱动的组织方式

(1)总线

总线其实是物理上本来就有的,他的英文名bus(公共汽车),总线的作用是将总线两端的设备连接起来,使他们能够通过总线进行通信(数据交互);那么驱动模型中

引入总线其实是借用了总线式的设计优点,与物理总线形成一个对应关系,能够更加方便的管理硬件设备。

(1.1)bus_type结构体

bus_type结构体是总线中用来创建一类总线时需要到的结构体,实际的总线根据自身的特点和要求对结构体进行填充形成具体的总线。

47.png


例如内核中ac97总线的定义:                                                           

 usb总线的定义  

  48.png

(2)设备

(2.1)设备驱动模型中的总线式设计中会包含设备和驱动两个,例如对于usb总线:usb_device和usb_driver ;对于platform总线:platform_device和platform_driver

他们中会包含相应的基类设备和基类驱动:struct device和struct device_driver,就好比和上面的驱动模型中所有对象都包含了基类kobject,所以对于所有具体总线

中的设备结构体中包含了基类struct device,驱动结构体中包含了基类struct device_driver。

而本段谈论的是struct device结构体,也就是设备。

(2.2)struct device是硬件设备在内核驱动框架中的抽象

(2.3)通常device不会单独使用,而是被包含在一个具体设备结构体中,如struct usb_device。就是上面说的被包含到一个具体的总线下的设备结构体中

struct device {
     struct device *parent;
     struct device_private *p;
     struct kobject kobj;         /* 包含一个kobject结构体,因为属于设备驱动模型中的一个对象 */
     const char *init_name; 
     struct device_type *type;
     struct mutex mutex;    
     struct bus_type    *bus;        
     struct device_driver *driver;    
     void *platform_data;        /* 这个是一个void类型的指针,用来指向这个设备特有的数据结构,数据结构类型由自己的定义,后面的led驱动就是使用了这个自定义结构体来存放设备的信息:GPIO等,而没有使用总线下的资源结构体 */
     struct dev_pm_info power;
 
 #ifdef CONFIG_NUMA
     int        numa_node;    
 #endif
 
     u64    *dma_mask;    
     u64    coherent_dma_mask;
     struct device_dma_parameters *dma_parms;
     struct list_head dma_pools;    
     struct dma_coherent_mem    *dma_mem; 
     struct dev_archdata    archdata;
     
 #ifdef CONFIG_OF
     struct device_node *of_node;
 #endif
 
     dev_t devt;    
     spinlock_t devres_lock;
     struct list_head devres_head;
     struct klist_node knode_class;
     struct class *class;
     void  (*release)(struct device *dev);  /* 当我们卸载设备时调用时调用的函数 */
 };

(3)驱动(struct device_driver)

跟上面一样,struct device_driver是驱动程序在内核驱动模型中的抽象,结构体如下:重点是关注name和probe


 49.png

(4)类(class)

class的真正意义在于作为同属于一个class的多个设备的容器。也就是说,class是一种人造概念,目的就是为了对各种设备进行分类管理。当然,class在分类的

同时还对每个类贴上了一些“标签”,这也是设备驱动模型为我们写驱动提供的基础设施。所以一个设备可以从类这个角度讲他是属于哪个类,也可以从总线的角度讲

他是挂在哪个总线下的。

mdev(嵌入式中用于自动创建设备节点和设备类的工具)的使用离不开class。

(4.1)相关结构体:struct class 和 struct class_device,这两个结构体我就不去看了。

5、设备驱动模型和设备驱动框架的关系

刚开始学设备驱动模型的时候,很容易搞混,我看老师有时候会把这两个概念搞在一起,我觉得有必要对这两个概念做一下区别。(以下纯属于我自己的理解)

(1)适用性范围:设备驱动框架其实是针对某一类具体的硬件设备而言的,不同的硬件设备都有针对他们本身特点的驱动框架,例如led就会存在led的驱动框架,flash就会有flash的

驱动框架,你就不能把led的驱动框架用在flash硬件设备上。而设备驱动模型之前说了它是用来管理硬件设备、使得驱动编写更加简单的一种软件体系,本身这套体系是很复杂的

,这套体系只有一套,能够对所有的硬件设备都是可行的。

(2)作用:设备驱动框架是内核中维护驱动相关的工程师们针对不同的硬件设备写的标准接口,他们已经将硬件设备相同的属性都封装起来了,留出来一些接口给我们具体的驱动开发工程师

来使用,其实这些标准接口也是使用最原始的内核提供的编写驱动相关的接口函数封装而来的,仅仅是为了使得驱动开发变得简单。而设备驱动模型是内核中构建实现的一套复杂的软件体系,

他的作用并不仅仅限于用在驱动的开发上,更多的是用来设备和设备驱动的管理上,也是为了应对现在越来越多的新特性。

(3)需要注意的是:我们是可以不基于驱动模型和不使用驱动框架来编写一个驱动程序,其实刚开始学习驱动的时候写的驱动就直接使用内核提供的最原始的接口函数来编写驱动的,

这一点是没有问题的,驱动也是能够正常运行的,当然对于复杂的设备可能比较困难。


发布手记

热门词条