linux设备模型深探.docx

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

linux设备模型深探.docx

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

linux设备模型深探.docx

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.\n");

}

 

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

{

       printk("haveshow.\n");

       printk("attrname:

%s.\n",attr->name);

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

       returnstrlen(attr->name)+2;

}

 

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

{

       printk("havestore\n");

       printk("write:

%s\n",buf);

       returncount;

}

 

structkobjectkobj;

staticintkobject_test_init()

{

       printk("kbojecttestinit.\n");

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

       return0;

}

 

staticintkobject_test_exit()

{

       printk("kobjecttestexit.\n");

       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]#echo hello>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!

\n");

        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!

\n",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'\n",

         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.\n",

                   __FUNCTION__,kobject_name(kobj));

        else

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

                   __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,structattribut

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

当前位置:首页 > 初中教育 > 理化生

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

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