linux驱动模型

linux驱动模型

linux2.5中引入linux驱动模型,有时也叫linux设备模型,主要解决之前版本存在的以下问题:

没有一种统一的机制表达驱动和设备之间的关系

没有通用的热插拔机制

没有通用的碘盐管理机制

4 procfs文件系统过度混乱,包含很多不是进程的信息

 

linux内核基于kobject内核对象机制将系统中的总线类型、设备和驱动分别用bus-type,device device_driver 等对象描述,并将其组织成一个层次结构的系统,同意管理各种类别(class)的设备及接口(class_interface) 同时借助sysfs文件系统将内核所见设备系统展示给用户控件,提供一个完全层次结构的用户视图

linux驱动模型的核心内容如下:

以内核对象为基础,内核对象kobject结构表示,相当于其他对象的基类,是构件linux驱动模型的关键,具有相同类型的内核对象构成内核对象集,用kset结构表示,内核对象集也包含自己的内核对象,从而组织成层次化的结构

sysfs文件系统导出到用户控件,内核中的所有内核对象组织成为树状,以对象属性为叶子,通过sysfs文件系统,将用户控件对文件的读写操作转化为对内核对象属性的显示与保存方法,从而导出内核对象信息,并提供配置接口

linux子系统表达为总线类型/驱动/设备//接口的关系,分别用bus_type. device, device_driver , class, class _interface结构表示,每个子系统都有自己的总线类型,他有一条驱动链表和一条设备链表,用来链接已经加载的驱动和已经发现的设备,驱动加载和设备发现的顺序可以是任意的,每个设备可以被绑定到最多一个驱动,被绑定了驱动的设备可以正常工作,除此之外,每个设备可以属于某个唯一的类,在类上包含多个接口,接口的方法被作用于设备,不管是先添加接口还是先发现设备。

 

引用计数

软件开发常常面对将一个分配好内存的对象多次传递并在多处使用,我们需要再程序动态运行的实现下,明确知道这些对象使用完毕的时机以便释放他所占用的内存,为此,引入引用计数:1)防止内存泄露:确保已分配的对象最终能被释放。2)防止访问已释放的内存:确保不会使用已经被释放的对象。

数据结构kref为任何内核数据结构添加引用计数提供一种简单有效方法,kref只有一个元素,结构如下

类型

描述

atomic_t

refcount

原子引用计算器

 

linux内核提供了以下函数对引用计数进行操作:

1 void kref_init(struct  kref *kref) 将对象引用计数设置为1

2 void kref_get(struct  kref*kref) 递增对象的引用计算,在这个之前,确保引用计数不为0,为了防止不先调用kref_init而直接调用kref_get

3 int kref_put(struct kref*kref ,void (*release)(struct kref*kref));递减对象的引用计数,如果计数为0表明是该对象的最后一个引用,因此传入的release函数被调用,回收这个对象用到的内存

这样,就可以将kref结构嵌入到需要使用引用计数的结构中了。然后在需要使用某个结构之前,先递增引用计数,用完后调用kref_put释放引用

而通过contain_of(pointer, type, member)实现通过引用计数的指针得到指向包含他的类型为type的结构的指针。

 

linux中实现循环双链表的list_head结构

在传统的双循环链表中,如果创建某种数据结构的双循环链表,通常是在这个数据结构中加入一个nextpre指针。

 

这种方式,用来维护链表的nextpre指针都是指向具体对应类型的对象因此一种数据结构的链表操作函数不能用于操作其他数据结构的链表。于是linux内核采用了一种类型无关的双循环链表实现方式,主要思想是将nextpre从具体的数据结构中提取出来成为一种通用的双链表数据结构list_head,.list_head作为一个成员被嵌入到要拉链的数据结构(宿主结构)中,这样,只需要一套通用的链表操作函数就可以将list_head成员作为连接件,把宿主结构链接起来,将链接件转为宿主结构还是使用contain_of宏。

 

内核对象及集合

linux驱动模型的基础是内核对象,他将总线类型、设备、驱动等都看做是内核对象。表示内核对象的结构是kobject,相当是linux驱动模型的基类。应该说每个Kobject结构都对应一个 目录。for example/sys/bus/pci/drivers/serial/ 路径, serial这个目录就是由一个kobject 结构体 来表示的。由此可见,Kobject是用来表示 直接对应着一个 设备,或设备驱动  的目录。Kobject包含了 这个目录的一些信息,如:目录名,父目录,设备名称等等一些信息。当然,如果Kobject用来表示一个目录,那么他所包含的信息是差不多了,但是Kobject表示的目录是用来描述某一个设备/设备驱动 的。所以仅仅Kobject这个结构体还不能完全的描述这个设备/设备驱动,再所以,Kobject这个结构体不会单独使用,一般都会包含在另一个结构体中,用网络上的话说就是包含在一个容器中。这个容器可以是:device结构体,device_drive结构体。现在层次就很明显了,device/device_drive来表示一个设备/设备驱动,当然包含了这个设备/设备驱动的信息,并且还包含了这个驱动所对应的目录的信息,Kobject结构

struct kobject {

    const char        *name;     //目录的name

struct list_head    entry;           //Kobject插入到某个链表的指针。也就是将kobject 

                                  链接到kset的连接件

struct kobject     *parent;  //父目录,刚才所述kobject所表示的是设备/设备驱动目

                        录,但为什么他的父目录也用kobject来表示呢?后面讲解。

struct kset        *kset;    //如果kobject已经链接到kset则指向之

struct kobj_type    *ktype; //kobject的类型

struct sysfs_dirent    *sd;//指向kobjectsysfs内部树中的节点

    struct kref        kref;   //被引用的次数

    unsigned int state_initialized:1;//kobject是否初始化

    unsigned int state_in_sysfs:1;//1表示kobject已经添加到内核关系树中

unsigned int state_add_uevent_sent:1;//是否支持热插?如果为1表示kobject已经发送添 

                                加事件到用户空间

unsigned int state_remove_uevent_sent:1;//是否支持热拔?为1表示已发送删除事件到用

                                  户空间

unsigned int uevent_suppress:1;//1表示抑制发送事件到用户空间。

};

kobject中有些成员或方法是内核对象类型特定的,也就是,对该类型的所有内核对象,这些成员和方法是相同的,其中一个明显的例子就是前边说到的release方法,虽说不同类型对象的release不同但是同一类型的release相同,只是以不同的对象实例为参数,其他例子还有该类型内核对象的默认属性,以及该类型内核对象的属性读写实现方法,这些类型特定的域,被提取出来定义成kobj_type结构

struct kobj_type

{

    void (*release)(struct kobject *);//释放kobject和其他占用资源的函数

struct sysfs_ops * sysfs_ops;//指向操作表结构的指针,实现该类型内核对象的属性读写 方法

    struct attribute ** default_attrs;//这种类型的内核对象的默认属性

 };

某种程度上,kset看上去像kobj_type结构的扩展,他表示内核对象的集合,但是,kobj_type关注于对象的类型,而kset强调对象的聚合或集合.

每个Kobject结构都对应一个 目录。for example/sys/bus/pci/drivers/serial/ 路径, /serial/这个目录由一个kobject 结构体 来表示的。但是/serial/的上一级目录/drivers/如何表示呢?那么就出现了Kset这个结构体。

struct kset {

struct list_head list; //kset下面的各个子目录的kobject

spinlock_t list_lock;//遍历这个kset的所有kobject的自旋锁

struct kobject kobj;//神奇的kobject,kset也仅仅是一个特殊的kobject而已

const struct kset_uevent_ops *uevent_ops;//这个ksetuevent操作集,相应函数在kobject发 生了某种事件时候被调用,kset可以添加新的环境变量,或者过滤掉一些uevent

};

以上,kset是一个顶层包含类,kset包含一系列kobject,把他们组织成为一个链表,ksetlist域为表头,被包含的kobject通过entry域链入这个链表,kobject还通过kset域指向包含他的kset


 

虽然图中给出ksetkobject的关系,但kobject一般是嵌套在其他的数据结构中的。

这样,kobject被组织成层次结构,kset存在是为了对层次在他之下的kobject施行相同模式的操作,kset定义了一个uevent操作表,对于一个层次在他之下的kobject,并且层次路径上没有其他的kset如果这个kobject上发生了某种事件就会调用操作表中相应的函数,以便通知用户空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值