linux设备模型深探.docx

上传人:b****4 文档编号:5052755 上传时间:2022-12-12 格式:DOCX 页数:32 大小:35.41KB
下载 相关 举报
linux设备模型深探.docx_第1页
第1页 / 共32页
linux设备模型深探.docx_第2页
第2页 / 共32页
linux设备模型深探.docx_第3页
第3页 / 共32页
linux设备模型深探.docx_第4页
第4页 / 共32页
linux设备模型深探.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

linux设备模型深探.docx

《linux设备模型深探.docx》由会员分享,可在线阅读,更多相关《linux设备模型深探.docx(32页珍藏版)》请在冰豆网上搜索。

linux设备模型深探.docx

linux设备模型深探

linux设备模型深探

时间:

2010-09-2313:

25:

02来源:

网络作者:

未知点击:

452次

一:

前言

Linux设备模型是一个极其复杂的结构体系,在编写驱动程序的时候,通常不会用到这方面的东西,但是。

理解这部份内容,对于我们理解linux设备驱动的结构是大有裨益的。

我们不但可以在编写程序程序的时候知其然,亦知其所以

一:

前言

Linux设备模型是一个极其复杂的结构体系,在编写驱动程序的时候,通常不会用到这方面的东西,但是。

理解这部份内容,对于我们理解linux设备驱动的结构是大有裨益的。

我们不但可以在编写程序程序的时候知其然,亦知其所以然。

又可以学习到一种极其精致的架构设计方法。

由于之前已经详细分析了sysfs文件系统。

所以本节的讨论主要集中在设备模型的底层实现上。

上层的接口,如pci.,usb,网络设备都可以看成是底层的封装。

二:

kobject,kset和ktype

Kobject,kset,kypte这三个结构是设备模型中的下层架构。

模型中的每一个元素都对应一个kobject.kset和ktype可以看成是kobject在层次结构与属性结构方面的扩充。

将三者之间的关系用图的方示描述如下:

如上图所示:

我们知道。

在sysfs中每一个目录都对应一个kobject.这些kobject都有自己的parent。

在没有指定parent的情况下,都会指向它所属的kset->object。

其次,kset也内嵌了kobject.这个kobject又可以指它上一级的parent。

就这样。

构成了一个空间上面的层次关系。

其实,每个对象都有属性。

例如,电源管理,执插拨事性管理等等。

因为大部份的同类设备都有相同的属性,因此将这个属性隔离开来,存放在ktype中。

这样就可以灵活的管理了.记得在分析sysfs的时候。

对于sysfs中的普通文件读写操作都是由kobject->ktype->sysfs_ops来完成的.

经过上面的分析,我们大概了解了kobject.kset与ktype的大概架设与相互之间的关系。

下面我们从linux源代码中的分析来详细研究他们的操作。

三:

kobject,kset和ktype的操作

为了说明kobject的操作,先写一个测试模块,代码如下:

#include

#include

#include

#include

#include

#include

#include

MODULE_AUTHOR("ericxiao");

MODULE_LICENSE("DualBSD/GPL");

voidobj_test_release(structkobject*kobject);

ssize_teric_test_show(structkobject*kobject,structattribute*attr,char*buf);

ssize_teric_test_store(structkobject*kobject,structattribute*attr,constchar*buf,size_tcount);

structattributetest_attr={

.name="eric_xiao",

.mode=S_IRWXUGO,

};

staticstructattribute*def_attrs[]={

&test_attr,

NULL,

};

structsysfs_opsobj_test_sysops=

{

.show=eric_test_show,

.store=eric_test_store,

};

structkobj_typektype=

{

.release=obj_test_release,

.sysfs_ops=&obj_test_sysops,

.default_attrs=def_attrs,

};

voidobj_test_release(structkobject*kobject)

{

printk("eric_test:

release.");

}

ssize_teric_test_show(structkobject*kobject,structattribute*attr,char*buf)

{

printk("haveshow.");

printk("attrname:

%s.",attr->name);

sprintf(buf,"%s",attr->name);

returnstrlen(attr->name)+2;

}

ssize_teric_test_store(structkobject*kobject,structattribute*attr,constchar*buf,size_tcount)

{

printk("havestore");

printk("write:

%s",buf);

returncount;

}

structkobjectkobj;

staticintkobject_test_init()

{

printk("kbojecttestinit.");

kobject_init_and_add(&kobj,&ktype,NULL,"eric_test");

return0;

}

staticintkobject_test_exit()

{

printk("kobjecttestexit.");

kobject_del(&kobj);

return0;

}

module_init(kobject_test_init);

module_exit(kobject_test_exit);

加载模块之后,会发现,在/sys下多了一个eric_test目录。

该目录下有一个叫eric_xiao的文件。

如下所示:

[root@localhosteric_test]#ls

eric_xiao

用cat察看此文件:

[root@localhosteric_test]#cateric_xiao

eric_xiao

再用echo往里面写点东西;

[root@localhosteric_test]#echohello>eric_xiao

Dmesg的输出如下:

haveshow.

attrname:

eric_xiao.

havestore

write:

hello

如上所示。

我们看到了kobject的大概建立过程.我们来看一下kobject_init_and_add()的实现。

在这个函数里,包含了对kobject的大部份操作。

intkobject_init_and_add(structkobject*kobj,structkobj_type*ktype,

structkobject*parent,constchar*fmt,...)

{

va_listargs;

intretval;

//初始化kobject

kobject_init(kobj,ktype);

va_start(args,fmt);

//为kobjcet设置名称,在sysfs中建立相关信息

retval=kobject_add_varg(kobj,parent,fmt,args);

va_end(args);

returnretval;

}

上面的流程主要分为两部份。

一部份是kobject的初始化。

在这一部份,它将kobject与给定的ktype关联起来。

初始化kobject中的各项结构。

另一部份是kobject的名称设置。

空间层次关系的设置,具体表现在sysfs文件系统中.

对于第一部份,代码比较简单,这里不再赘述。

跟踪第二部份,也就是kobject_add_varg()的实现.

staticintkobject_add_varg(structkobject*kobj,structkobject*parent,

constchar*fmt,va_listvargs)

{

va_listaq;

intretval;

va_copy(aq,vargs);

//设置kobject的名字。

即kobject的name成员

retval=kobject_set_name_vargs(kobj,fmt,aq);

va_end(aq);

if(retval){

printk(KERN_ERR"kobject:

cannotsetnameproperly!

");

returnretval;

}

//设置kobject的parent。

在上面的例子中,我们没有给它指定父结点

kobj->parent=parent;

//在sysfs中添加kobjcet信息

returnkobject_add_internal(kobj);

}

设置好kobject->name后,转入kobject_add_internal()。

在sysfs中创建空间结构.代码如下:

staticintkobject_add_internal(structkobject*kobj)

{

interror=0;

structkobject*parent;

if(!

kobj)

return-ENOENT;

//如果kobject的名字为空.退出

if(!

kobj->name||!

kobj->name[0]){

pr_debug("kobject:

(%p):

attemptedtoberegisteredwithempty"

"name!

",kobj);

WARN_ON

(1);

return-EINVAL;

}

//取kobject的父结点

parent=kobject_get(kobj->parent);

//如果kobject的父结点没有指定,就将kset->kobject做为它的父结点

/*joinksetifset,useitasparentifwedonotalreadyhaveone*/

if(kobj->kset){

if(!

parent)

parent=kobject_get(&kobj->kset->kobj);

kobj_kset_join(kobj);

kobj->parent=parent;

}

//调试用

pr_debug("kobject:

'%s'(%p):

%s:

parent:

'%s',set:

'%s'",

kobject_name(kobj),kobj,__FUNCTION__,

parent?

kobject_name(parent):

"",

kobj->kset?

kobject_name(&kobj->kset->kobj):

"");

//在sysfs中创建kobject的相关元素

error=create_dir(kobj);

if(error){

//v如果创建失败。

减少相关的引用计数

kobj_kset_leave(kobj);

kobject_put(parent);

kobj->parent=NULL;

/*benoisyonerrorissues*/

if(error==-EEXIST)

printk(KERN_ERR"%sfailedfor%swith"

"-EEXIST,don'ttrytoregisterthingswith"

"thesamenameinthesamedirectory.",

__FUNCTION__,kobject_name(kobj));

else

printk(KERN_ERR"%sfailedfor%s(%d)",

__FUNCTION__,kobject_name(kobj),error);

dump_stack();

}else

//如果创建成功。

将state_in_sysfs建为1。

表示该object已经在sysfs中了

kobj->state_in_sysfs=1;

returnerror;

}

这段代码比较简单,它主要完成kobject父结点的判断和选定,然后再调用create_dir()在sysfs创建相关信息。

该函数代码如下:

staticintcreate_dir(structkobject*kobj)

{

interror=0;

if(kobject_name(kobj)){

//为kobject创建目录

error=sysfs_create_dir(kobj);

if(!

error){

//为kobject->ktype中的属性创建文件

error=populate_dir(kobj);

if(error)

sysfs_remove_dir(kobj);

}

}

returnerror;

}

我们在上面的示例中看到的/sys下的eric_test目录,以及该目录下面的eric_xiao的这个文件就是这里被创建的。

我们先看一下kobject所表示的目录创建过程。

这是在sysfs_create_dir()中完成的。

代码如下:

intsysfs_create_dir(structkobject*kobj)

{

structsysfs_dirent*parent_sd,*sd;

interror=0;

BUG_ON(!

kobj);

/*如果kobject的parnet存在。

就在目录点的目录下创建这个目录。

如果没有父结点不存在,就在/sys下面创建结点。

在上面的流程中,我们可能并没有为其指定父结点,也没有为其指定kset。

*/

if(kobj->parent)

parent_sd=kobj->parent->sd;

else

parent_sd=&sysfs_root;

//在sysfs中创建目录

error=create_dir(kobj,parent_sd,kobject_name(kobj),&sd);

if(!

error)

kobj->sd=sd;

returnerror;

}

在这里,我们就要联系之前分析过的sysfs文件系统的研究了。

如果不太清楚的,可以在找到那篇文章仔细的研读一下。

create_dir()就是在sysfs中创建目录的接口,在之前已经详细分析过了。

这里不再讲述。

接着看为kobject->ktype中的属性创建文件。

这是在populate_dir()中完成的。

代码如下:

staticintpopulate_dir(structkobject*kobj)

{

structkobj_type*t=get_ktype(kobj);

structattribute*attr;

interror=0;

inti;

if(t&&t->default_attrs){

for(i=0;(attr=t->default_attrs[i])!

=NULL;i++){

error=sysfs_create_file(kobj,attr);

if(error)

break;

}

}

returnerror;

}

这段代码比较简单。

它遍历ktype中的属性。

然后为其建立文件。

请注意:

文件的操作最后都会回溯到ktype->sysfs_ops的show和store这两个函数中.

Kobject的创建已经分析完了,接着分析怎么将一个kobject注销掉。

注意过程是在kobject_del()中完成的。

代码如下:

voidkobject_del(structkobject*kobj)

{

if(!

kobj)

return;

sysfs_remove_dir(kobj);

kobj->state_in_sysfs=0;

kobj_kset_leave(kobj);

kobject_put(kobj->parent);

kobj->parent=NULL;

}

该函数会将在sysfs中的kobject对应的目录删除。

请注意,属性文件是建立在这个目录下面的。

只需要将这个目录删除。

属性文件也随之删除。

是后,减少相关的引用计数,如果kobject的引用计数为零。

则将其所占空间释放.

Kset的操作与kobject类似,因为kset中内嵌了一个kobject结构,所以,大部份操作都是集中在kset->kobject上.具体分析一下kset_create_and_add()这个接口,类似上面分析的kobject接口,这个接口也包括了kset的大部分操作.代码如下:

structkset*kset_create_and_add(constchar*name,

structkset_uevent_ops*uevent_ops,

structkobject*parent_kobj)

{

structkset*kset;

interror;

//创建一个kset

kset=kset_create(name,uevent_ops,parent_kobj);

if(!

kset)

returnNULL;

//注册kset

error=kset_register(kset);

if(error){

//如果注册失败,释放kset

kfree(kset);

returnNULL;

}

returnkset;

}

Kset_create()用来创建一个structkset结构.代码如下:

staticstructkset*kset_create(constchar*name,

structkset_uevent_ops*uevent_ops,

structkobject*parent_kobj)

{

structkset*kset;

kset=kzalloc(sizeof(*kset),GFP_KERNEL);

if(!

kset)

returnNULL;

kobject_set_name(&kset->kobj,name);

kset->uevent_ops=uevent_ops;

kset->kobj.parent=parent_kobj;

kset->kobj.ktype=&kset_ktype;

kset->kobj.kset=NULL;

returnkset;

}

我们注意,在这里创建kset时.为其内嵌的kobject指定其ktype结构为kset_ktype.这个结构的定义如下:

staticstructkobj_typekset_ktype={

.sysfs_ops=&kobj_sysfs_ops,

.release=kset_release,

};

属性文件的读写操作全部都包含在sysfs_ops成员里.kobj_sysfs_ops的定义如下:

structsysfs_opskobj_sysfs_ops={

.show=kobj_attr_show,

.store=kobj_attr_store,

};

Show,store成员对应的函数代码如下所示:

staticssize_tkobj_attr_show(structkobject*kobj,structattribute*attr,

char*buf)

{

structkobj_attribute*kattr;

ssize_tret=-EIO;

kattr=container_of(attr,structkobj_attribute,attr);

if(kattr->show)

ret=kattr->show(kobj,kattr,buf);

returnret;

}

staticssize_tkobj_attr_store(structkobject*kobj,structattribute*attr,

constchar*buf,size_tcount)

{

structkobj_attribute*kattr;

ssize_tret=-EIO;

kattr=container_of(attr,structkobj_attribute,attr);

if(kattr->store)

ret=kattr->store(kobj,kattr,buf,count);

returnret;

}

从上面的代码看以看出.会将structattribute结构转换为structkobj_attribte结构.也就是说structkobj_attribte内嵌了一个structattribute.实际上,这是和宏__ATTR配合在一起使用的.经常用于group中.在这里并不打算研究group.原理都是一样的.这里列出来只是做个说明而已.

创建好了kset之后,会调用kset_register().这个函数就是kset操作的核心代码了.如下:

intkset_register(structkset*k)

{

interr;

if(!

k)

return-EINVAL;

kset_init(k);

err=kobject_add_internal(&k->kobj);

if(err)

returnerr;

kobject_uevent(&k->kobj,KOBJ_ADD);

return0;

}

在kset_init()里会初始化kset中的其它字段.然后调用kobject_add_internal()为其内嵌的kobject结构建立空间层次结构.之后因为添加了kset.会产生一个事件.这个事件是通过用户空间的hotplug程序处理的.这就是kset明显不同于ko

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1