设备模型和模块

为了提供更加统一的设备模型,2.6版本的内核对于设备驱动模块进行了很大的改动,而且这些改动现在还在继续。提出新的设备模型起初是为了电源管理。新的设备模型涉及了好几个部分:

1、模块机制,内核如何动态加载和卸载驱动模块。

Linux内核为了简单以及性能考虑,采用了宏内核和模块机制结合的设计。这样内核可以保持内核镜像大小合理,又可以动态加载模块,扩充功能。这种设计对于如今流行的热插拔很重要。

模块的开发和程序开发差不多,只是模块必须按照规范提供入口和出口。看一下流行的hello world用模块如何实现。

 

模块加载时调用入口函数,卸载时调用出口函数。模块入口函数的形式必须为int init_fun(void),而且函数如果成功执行,即模块初始化成功,必须返回0。如果失败,函数必须要能回滚,清除已初始化的部分。如已经分配了内存空间,如果在后面的操作中失败,则必须回滚释放所分配的内存。而入口函数则必须具有形式void exit_func(vodi),一般在入口函数中要分配资源,初始化硬件等,当然这里比较简单,只是输出一些语句。而入口函数则需要释放资源,重设硬件。

 

在模块中可以声明模块参数,这里不在赘述。

 

2、设备类型,主要包括块设备、字符设备、网络设备。

 

 

3、内核对象,利用内核对象,对系统内的设备进行组织,形成设备树。

内核对象(kernel object)对应的数据结构为struct kobject,与之相关的数据结构还包括kref,kset,kobj_type等。同时,开发者们还特意实现了一个虚拟文件系统sysfs,用来将系统中的内核对象结构导出到用户空间。

 

name:指向内核对象名称

parent:在内核中,所有的内核对象组织成一个树状结构,parent指向树状结构中本对象的父节点。

sd:在文件系统sysfs中,内核对象有一个对应的目录结构,这个成员便来能够就指向这个目录结构

kref:提供了一个引用技术的功能,它记录了kobject被引用了多少次。

 

kset:每个kobject都属于一个集合之中。kset就指向这个集合对应的结构体。既然有些内核对象属于同一个集合,那么如何管理这个集合?这就是成员变量entry的作用,他把属于同一集合的内核对象组织成双向链表。

 

list:作为一个容器,kset包含了很多Kobject结构,因此,list作为一个链表头,通过它,可以找到所有本集合内的内核对象。

list_lock:一个锁,为了防止同时操作链表而破坏链表结构。

kobj:集合kset在系统中也是作为内核对象进行管理的,因此他内部也嵌入了一个kobject结构体。

uevent_ops:为了在用户空间处理热插拔事件,开发者设计了一套机制。每当热插拔事件发生,内核会产生一个user event。而用户空间有一个线程uevent,专门用来处理这些事件。而uevent_ops则规定了如何处理这些事件。

 

kobj_type:每个kobject都对应一个特定的类型,这个类型由结构体struct kobj_type表示。这个结构包含了很多kobject的特定操作,如果多个内核对象属于同一类型,则它们会指向同一个kobj_type对象。

release:这个指针指向一个析构函数,每个kobject都有一个引用计数,当这个引用计数降为0时,会调用这个析构函数,释放一些资源,如名字等。

sysfs_ops:这个指针指向一个sysfs_ops结构体。前面说过,kobject结构会在sysfs文件系统中有对应的文件。而sysfs_ops这个结构体中包含一些函数,这些函数指示了如何操作sysfs系统文件。

default_attrs:这个指针指向一个attribute的数组,这个数组定义了这个kobject对象的一些属性,如果这个kobject导出到sysfs文件系统,其对应一个目录,而这些属性会成为这个目录中的文件。

 

和其他数据结构一样,kobject也总是被嵌入到更大的数据结构之中。内核中字符设备对应的数据结构struct cde就是这么做的。

4、Sysfs文件系统,这是一个位于内存中的虚拟文件系统,和proc文件系统类似,主要是用作将设备树导出到用户空间,当然还有一些属性。这样用户可以清楚的了解系统中设备结构,读取并修改部分属性。

kobject在文件系统中对应着目录。

假设你创建并初始化了一个kobject对象,但是它会不会自动将自己导出到sysfs中。

int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...);

该函数会根据这个kobject在结构树中的位置确定对应文件在文件系统中的位置。

void kobject_del(struct kobject *kobj);

将指定kobj从sysfs文件系统中删除。

 

前面讲过kobject对应的属性,这些属性在文件系统中对应一个文件。

name:属性的名字,一般作为该属性对应文件的名字。

owner:指向该属性所属的模块

mode:指明了对应文件的权限。

这个结构只是定义属性,那如何使用它们呢?看看kobj_type的定义,sysfs_ops的作用就是说明如何使用这些属性。

当用户试图读取属性时,会调用函数show,该函数会将属性attr拷贝到buffer中,并返回数据的长度。

当用户试图修改属性时,会调用函数sstore,该函数会将buffer中长度为size的数据拷贝到attr中,并返回实际写入数据的长度。

 

5、内核事件

在2.6版本的内核开始,内核事件机制开始出现,并逐步展示了其潜力。内核把kobject发送的信号包装成事件,每个事件的源都是kobject对应的文件路径。事件都被赋予一个字符串(但为了效率,安全等原因,实际上并没有采用字符串),来说明发生了什么。这样,用户空间的线程就可以明白发生了什么。

int kobject_uevent(struct kobject *kobj, enum kobject_action action);

第一个参数时发出信号的内核对象,而第二个参数则标明了事件的类型。前面说过这里并没有使用字符串,而是采用了枚举类型。如KOBJ_MOVEKOBJ_ONLINEKOBJ_OFFLINEKOBJ_ADDKOBJ_REMOVEKOBJ_CHANGE,这些值分别对应了"move","online","offline","add","remove","change"等字符串。

 

 

实际的驱动开发可能用不着这些东西,但了解一下总是好的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值