Linux设备驱动编程模型之上层容器篇(DOCX 33页).docx_第1页
Linux设备驱动编程模型之上层容器篇(DOCX 33页).docx_第2页
Linux设备驱动编程模型之上层容器篇(DOCX 33页).docx_第3页
Linux设备驱动编程模型之上层容器篇(DOCX 33页).docx_第4页
Linux设备驱动编程模型之上层容器篇(DOCX 33页).docx_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Linux设备驱动编程模型之上层容器篇 分类: Linux 2012-10-06 17:18 245人阅读 评论(0) 收藏 举报 linux编程struct数据结构listnull2.6内核增加了一个引人注目的新特性统一设备模型(devicemodel)。设备模型提供了一个独立的机制专门来表示设备,并描述其在系统中的拓扑结构,从而使得系统具有以下优点:l代码重复最小化。l提供诸如引用计数这样的统一机制。l可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线。l可以将系统中的全部设备结构以树的形式完整、有效的展现出来包括所有的总线和内部连接。l可以将设备和其对应的驱动联系起来,反之亦然。l可以将设备按照类型加以归类,比如分类为输入设备,而无需理解物理设备的拓扑结构。l可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确顺序关闭各设备的电源。最后一点是实现设备模型的最初动机。若想在内核中实现智能的电源管理,就需要来建立表示系统中设备拓扑关系的树结构。当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以下的(处于叶子上的)设备电源。比如内核需要先关闭一个USB鼠标,然后才可关闭USB控制器;同样内核也必须在关闭PCI总线前先关闭USB控制器。简而言之,若要准确而又高效的完成上述电源管理目标,内核无疑需要一颗设备树。一、原理虽然设备模型的初衷是为了方便电源管理而提供出的一种设备拓扑结构,但是,为了方便调试,设备模型的开发者决定将设备结构树导出为一个文件系统,这就是sysfs文件系统,它可以帮助用户能以一个简单文件系统的方式来观察系统中各种设备的拓扑结构。这个举措很快被证明是非常明智的,首先sysfs代替了先前处于/proc下的设备相关文件;另外它为系统对象提供了一个很有效的视图。实际上,sysfs起初被称为driverfs。最终sysfs使得我们认识到一个全新的对象模型非常有利于系统。今天所有2.6内核的系统都拥有sysfs文件系统,而且几乎都毫无例外的将其挂载。图一是挂载于/sys目录下的sysfs文件系统的局部视图。/sys|block/|fd0|hda|dev|device-././devices/pci0000:00/0000:00:1f.1/ide0/0.0|bus/|class/|devices/|firmware/|power/|module/Sysfs的根目录下包含了七个目录:block,bus,class,devices,firmware,module和power。block目录下的每个子目录都对应着系统中的一个块设备。反过来,每个目录下又都包含了该块设备的所有分区。bus目录提供了一个系统总线视图。class目录包含了以高层功能逻辑组织起来的系统设备视图。devices目录是系统中设备拓扑结构视图,它直接映射出了内核中设备结构体的组织层次。firmware目录包含了一些诸如ACPI,EDD,EFI等低层子系统的特殊树。power目录包含了系统范围的电源管理数据。其中最重要的目录是devices,该目录将设备模型导出到用户空间。目录结构就是系统中实际的设备拓扑。其它目录中的很多数据都是将devices目录下的数据加以转换加工而得。比如,/sys/class/net/目录是以注册网络接口这一高层概念来组织设备关系的,在这个目中可能会有目录eth0,它里面包含的devices文件其实就是一个指回到devices下实际设备目录的符号连接。随便看看任何你可访问到的Linux系统,这种系统设备视图相当准确和漂亮,而且可以看到class中的高层概念与devices中的低层物理设备,以及bus中的实际驱动程序之间互相联络是非常广泛的。Sysfs文件系统的目标就是要展现设备驱动模型组件之间的层次关系。在Linux中,sysfs文件系统被安装于/sys目录下:mount-tsysfssysfs/sys/sys|block/|fd0|hda|dev|device-././devices/pci0000:00/0000:00:1f.1/ide0/0.0|bus/|class/|devices/|firmware/|power/|module/那么,在这样的目录树中,哪些目录是驱动模型要关注的对象?bus-系统中用于连接设备的总线,在内核中对应的结构体为structbus_type;device-内核所识别的所有设备,依照连接它们的总线对其进行组织,对应的结构体为structdevice;class-系统中设备的类型(声卡,网卡,显卡,输入设备等),同一类中包含的设备可能连接到不同的总线,对应的结构体为structclass;为什么不对Power进行单独描述?实际上,Power与device有关,它只是device中的一个字段。除此之外,立马闪现在我们脑子里的对象还有:driver-在内核中注册的设备驱动程序,对应的结构体为structdevice_driver;以上bus,device,class,driver,是可以感受到的对象,在内核中都用相应的结构体来描述。而实际上,按照面向对象的思想,我们需要抽象出一个最基本的对象,这就是设备模型的核心对象kobject.Kobject是Linux2.6引入的新的设备管理机制,在内核中就是一个structkobject结构体。有了这个数据结构,内核中所有设备在底层都具有统一的接口,kobject提供基本的对象管理,是构成Linux2.6设备模型的核心结构,它与sysfs文件系统紧密关联,每个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录。Kobject是组成设备模型的基本结构。类似于C+中的基类,它嵌入于更大的对象中,即所谓的容器,如上面提到的bus,class,devices,drivers都是典型的容器,它们是描述设备模型的组件。二、主要对象介绍1,核心对象kobject话说kobject是驱动模型的核心对象,但在sysfs文件系统中似乎并没有对应的项,而这种看似“无”,实际上蕴藏着“有”。这“有”从何说起。回想文件系统中的核心对象“索引节点(indoe)”和目录项“dentry”:Inode与文件系统中的一个文件相对应(而实际上,只有文件被访问时,才在内存创建索引节点)。Dentry-每个路径中的一个分量,例如路径/bin/ls,其中/、bin和ls三个都是目录项,只是前两个是目录,而最后一个是普通文件。也就是说,目录项目录项或者是一子目录,或者是一个文件。从上面的定义可以看出,indoe和dentry谁的包容性更大?当然是dentry!那么,kobject与dentry有何关系?由此我们可以推想,把dentry作为kobject中的一个字段,恍然间,kobject变得强大起来了。何谓“强大“,因为这样以来,就可以方便地将kobject映射到一个dentry上,也就是说,kobject与/sys下的任何一个目录或文件相对应了,进一步说,把kobject导出形成文件系统就变得如同在内存中构建目录项一样简单。由此可知,kobject其实已经形成一棵树了。这就是以隐藏在背后的对象模型为桥梁,将驱动模型和sysfs文件系统全然联系起来。由于kobject被映射到目录项,同时对象模型层次结构也已经在内存形成一个树,因此sysfs的形成就水到渠成了。既然,kobject要形成一颗树,那么其中的字段就要有parent,以表示树的层次关系;另外,kobject不能是无名氏,得有name字段,按说,目录或文件名并不会很长,但是,sysfs文件系统为了表示对象之间复杂的关系,需要通过软链接达到,而软链接常常有较长的名字。cpp view plaincopyprint?1. /*设备驱动程序模型的核心数据结构,每个kobject2. 数据结构对应于sysfs文件系统中的一个目录*/3. structkobject4. constchar*name;/*指向含有容器名称的字符*/5. structlist_headentry;/*用于kobject所插入的链表的指针*/6. structkobject*parent;/*指向父kobject*/7. structkset*kset;/*指向包含的kset*/8. structkobj_type*ktype;/*指向kobject的类型的描述符*/9. structsysfs_dirent*sd;/*用同一种structsysfs_dirent来统一设备模型中的kset/kobject/attr/attr_group.*/10. structkrefkref;/*容器的引用计数器*/11. unsignedintstate_initialized:1;/*指明kobject是否被初始化*/12. unsignedintstate_in_sysfs:1;/*指明是否使用了sysfs*/13. unsignedintstate_add_uevent_sent:1;/*热插拔加载事件*/14. unsignedintstate_remove_uevent_sent:1;/*热插拔卸载事件*/15. unsignedintuevent_suppress:1;/*如果设置了uevent_suppress字段,说明不希望产生事件,忽略事件正确返回*/16. ;cpp view plaincopyprint?1. /*设备驱动程序模型的核心数据结构,每个kobject2. 数据结构对应于sysfs文件系统中的一个目录*/3. structkobject4. constchar*name;/*指向含有容器名称的字符*/5. structlist_headentry;/*用于kobject所插入的链表的指针*/6. structkobject*parent;/*指向父kobject*/7. structkset*kset;/*指向包含的kset*/8. structkobj_type*ktype;/*指向kobject的类型的描述符*/9. structsysfs_dirent*sd;/*用同一种structsysfs_dirent来统一设备模型中的kset/kobject/attr/attr_group.*/10. structkrefkref;/*容器的引用计数器*/11. unsignedintstate_initialized:1;/*指明kobject是否被初始化*/12. unsignedintstate_in_sysfs:1;/*指明是否使用了sysfs*/13. unsignedintstate_add_uevent_sent:1;/*热插拔加载事件*/14. unsignedintstate_remove_uevent_sent:1;/*热插拔卸载事件*/15. unsignedintuevent_suppress:1;/*如果设置了uevent_suppress字段,说明不希望产生事件,忽略事件正确返回*/16. ;/*设备驱动程序模型的核心数据结构,每个kobject数据结构对应于sysfs文件系统中的一个目录*/struct kobject const char*name;/*指向含有容器名称的字符*/struct list_headentry;/*用于kobject所插入的链表的指针*/struct kobject*parent;/*指向父kobject*/struct kset*kset;/*指向包含的kset*/struct kobj_type*ktype;/*指向kobject的类型的描述符*/struct sysfs_dirent*sd;/*用同一种 struct sysfs_dirent 来统一设备模型中的 kset/kobject/attr/attr_group.*/struct krefkref;/*容器的引用计数器*/unsigned int state_initialized:1;/*指明kobject是否被初始化*/unsigned int state_in_sysfs:1;/*指明是否使用了sysfs*/unsigned int state_add_uevent_sent:1;/*热插拔加载事件*/unsigned int state_remove_uevent_sent:1;/*热插拔卸载事件*/unsigned int uevent_suppress:1;/*如果设置了uevent_suppress字段,说明不希望产生事件,忽略事件正确返回*/;2.引用计数krefkobject的主要功能之一就是为我们提供了一个统一的引用计数系统,为什么说它具有“统一”的能力?那是因为kobject是“基”对象,就像大厦的基地,其他对象(如devic,bus,class,device_driver等容器)都将其包含,以后,其他对象的引用技术继承或封装kobject的引用技术就可以了。初始化时,kobject的引用计数设置为1。只要引用计数不为零,那么该对象就会继续保留在内存中,也可以说是被“钉住”了。任何包含对象引用的代码首先要增加该对象的引用计数,当代码结束后则减少它的引用计数。增加引用计数称为获得(getting)对象的引用,减少引用计数称为释放(putting)对象的引用。当引用计数跌到零时,对象便可以被销毁,同时相关内存也都被释放。增加一个引用计数可通过koject_get()函数完成:structkobject*kobject_get(structkobject*kobj);该函数正常情况下将返回一个指向kobject的指针,如果失败则返回NULL指针;减少引用计数通过kobject_put()完成:voidkobject_put(structkobject*kobj);如果对应的kobject的引用计数减少到零,则与该kobject关联的ktype中的析构函数将被调用。我们深入到引用计数系统的内部去看,会发现kobject的引用计数是通过kref结构体实现的,该结构体定义在头文件中:structkrefatomic_trefcount;其中唯一的字段是用来存放引用计数的原子变量。那为什么采用结构体?这是为了便于进行类型检测。在使用kref前,必须先通过kref_init()函数来初始化它:void kref_init(struct kref *kref) atomic_set(&kref-refcount, 1);正如你所看到的,这个函数简单的将原子变量置1,所以kref一但被初始化,它表示的引用计数便固定为1。开发者现在不必在内核代码中利用atmoic_t类型来实现其自己的引用计数。对开发者而言,在内核代码中最好的方法是利用kref类型和它相应的辅助函数,为自己提供一个通用的、正确的引用计数机制。上述的所有函数定义与声明分别在在文件lib/kref.c和文件中。3.共同特性的ktype如上所述,kobject是一个抽象而基本的对象。对于一族具有共同特性的kobject,就是用ktype来描述:cpp view plaincopyprint?1. structkobj_type2. void(*release)(structkobject*kobj);3. structsysfs_ops*sysfs_ops;4. structattribute*default_attrs;5. ;cpp view plaincopyprint?1. structkobj_type2. void(*release)(structkobject*kobj);3. structsysfs_ops*sysfs_ops;4. structattribute*default_attrs;5. ;struct kobj_type void (*release)(struct kobject *kobj);struct sysfs_ops *sysfs_ops;struct attribute *default_attrs;定义于头文件中。release指针指向在kobject引用计数减至零时要被调用的析构函数。该函数负责释放所有kobject使用的内存和其它相关清理工作。sysfs_ops变量指向sysfs_ops结构体,其中包含两个函数,也就是对属性进行操作的读写函数show()和store()。最后,default_attrs指向一个attribute结构体数组。这些结构体定义了kobject相关的默认属性。属性描述了给定对象的特征,其实,属性就是对应/sys树形结构中的叶子结点,也就是文件。4.对象集合体ksetKset,顾名思义就是kobject对象的集合体,可以把它看成是一个容器,可将所有相关的kobject对象聚集起来,比如“全部的块设备”就是一个kset。听起来kset与ktypes非常类似,好像没有多少实质内容。那么“为什么会需要这两个类似的东西呢”。ksets可把kobject集中到一个集合中,而ktype描述相关类型kobject所共有的特性,它们之间的重要区别在于:具有相同ktype的kobject可以被分组到不同的ksets。kobject的kset指针指向相应的kset集合。kset集合由kset结构体表示,定义于头文件中:cpp view plaincopyprint?1. structkset2. structlist_headlist;/*包含在kset中的kobject类型的描述符*/3. spinlock_tlist_lock;4. /*嵌入的kobject结构,位于kset中的kobject,其parent字段指向这个内嵌的5. kobject指针*/6. structkobjectkobj;7. /*指向用于处理kobject结构的过滤和热插拔操作的回调函数表*/8. structkset_uevent_ops*uevent_ops;9. ;cpp view plaincopyprint?1. structkset2. structlist_headlist;/*包含在kset中的kobject类型的描述符*/3. spinlock_tlist_lock;4. /*嵌入的kobject结构,位于kset中的kobject,其parent字段指向这个内嵌的5. kobject指针*/6. structkobjectkobj;7. /*指向用于处理kobject结构的过滤和热插拔操作的回调函数表*/8. structkset_uevent_ops*uevent_ops;9. ;struct kset struct list_head list;/*包含在kset中的kobject类型的描述符*/spinlock_t list_lock;/*嵌入的kobject结构,位于kset中的kobject,其parent字段指向这个内嵌的kobject指针*/struct kobject kobj;/*指向用于处理kobject结构的过滤和热插拔操作的回调函数表*/struct kset_uevent_ops *uevent_ops;其中ktype指针指向集合(kset)中kobject对象的类型(ktype),list连接该集合(kset)中所有的kobject对象。kobj指向的koject对象代表了该集合的基类,uevent_ops指向一个用于处理集合中kobject对象的热插拔操作的结构体。5,sys文件系统目录实体sysfs_direntsysfs文件系统有自己的dirent结构,dirent=directoryentry(目录实体)。sysfs中,每一个dentry对应了一个dirent结构,dentry-d_fsdata是一个void的指针,它指向sysfs_dirent结构。每个kobject结构对应一个dirent结构。每个文件(包括目录文件)都对应一个sysfs_dirent对象,在建立目录和文件后,内存中会形成一棵以sysfs_root为根的目录树结构。属性attribute结构对应sysfs中的文件,也用sysfs_dirent结构表示。这样sysfs_dirent的组织就是sysfs的树形结构的映射。cpp view plaincopyprint?1. /*structsysfs_dirent就是用来做kobject与dentry的互相转换用的*/2. structsysfs_dirent3. atomic_ts_count;4. atomic_ts_active;5. structsysfs_dirent*s_parent;6. structsysfs_dirent*s_sibling;7. constchar*s_name;8. /*共用体包含四种不同的结构,分别是目录、9. 符号链接文件、属性文件、二进制属性文件10. 其中目录类型可以对应kobject,在相应的s_dir11. 中也有对kobject的指针,因此在内核数据结12. 构,kobject与sysfs_dirent是互相引用的;13. */14. union15. structsysfs_elem_dirs_dir;16. structsysfs_elem_symlinks_symlink;17. structsysfs_elem_attrs_attr;18. structsysfs_elem_bin_attrs_bin_attr;19. ;20. 21. unsignedints_flags;22. ino_ts_ino;23. umode_ts_mode;24. structsysfs_inode_attrs*s_iattr;25. ;cpp view plaincopyprint?1. /*structsysfs_dirent就是用来做kobject与dentry的互相转换用的*/2. structsysfs_dirent3. atomic_ts_count;4. atomic_ts_active;5. structsysfs_dirent*s_parent;6. structsysfs_dirent*s_sibling;7. constchar*s_name;8. /*共用体包含四种不同的结构,分别是目录、9. 符号链接文件、属性文件、二进制属性文件10. 其中目录类型可以对应kobject,在相应的s_dir11. 中也有对kobject的指针,因此在内核数据结12. 构,kobject与sysfs_dirent是互相引用的;13. */14. union15. structsysfs_elem_dirs_dir;16. structsysfs_elem_symlinks_symlink;17. structsysfs_elem_attrs_attr;18. structsysfs_elem_bin_attrs_bin_attr;19. ;20. 21. unsignedints_flags;22. ino_ts_ino;23. umode_ts_mode;24. structsysfs_inode_attrs*s_iattr;25. ;/*struct sysfs_dirent就是用来做kobject与dentry的互相转换用的*/struct sysfs_dirent atomic_ts_count;atomic_ts_active;struct sysfs_dirent*s_parent;struct sysfs_dirent*s_sibling;const char*s_name;/*共用体包含四种不同的结构,分别是目录、符号链接文件、属性文件、二进制属性文件其中目录类型可以对应 kobject,在相应的 s_dir 中也有对 kobject 的指针,因此在内核数据结构, kobject 与 sysfs_dirent 是互相引用的;*/union struct sysfs_elem_dirs_dir;struct sysfs_elem_symlinks_symlink;struct sysfs_elem_attrs_attr;struct sysfs_elem_bin_attrs_bin_attr;unsigned ints_flags;ino_ts_ino;umode_ts_mode;struct sysfs_inode_attrs *s_iattr;下面是设备驱动模型核心数据结构关系图总结:kobject通常是嵌入到其它结构中的,其单独意义其实并不大。相反,那些更为重要的结构体,比如在structcdev中才真正需要用到kobject结构。cpp view plaincopyprint?1. structcdev2. structkobjectkobj;3. structmodule*owner;4. conststructfile_operations*ops;5. structlist_headlist;6. dev_tdev;7. unsignedintcount;8. ;cpp view plaincopyprint?1. structcdev2. structkobjectkobj;3. structmodule*owner;4. conststructfile_operations*ops;5. structlist_headlist;6. dev_tdev;7. unsignedintcount;8. ;struct cdev struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;当kobject被嵌入到其它结构中时,该结构便拥有了kobject提供的标准功能。更重要的一点是,嵌入kobject的结构体可以成为对象层次架构中的一部分。比如cdev结构体就可通过其父指针cdev-kobj-parent和链表cdev-kobj-entry来插入到对象层次结构中三、主要方法对设备驱动模型中核心的数据结构做了总结,对他们的操作就不难理解了,可以猜得到都是根据上面关系图来实现的方法。对每个数据结构都有很多实现的函数,这里我们只分析一个,即kset的注册。这个函数的实现涉及到了上面的所有数据结构。我也是根据这个函数画出上面的关系图的。kset注册cpp view plaincopyprint?1. /*2. *kset_register-initializeandaddakset.3. *k:kset.4. */5. intkset_register(structkset*k)6. 7. interr;8. 9. if(!k)10. return-EINVAL;11. /*基本的初始化*/12. kset_init(k);13. /*kobj以及其属性建立sd树*/14. err=kobject_add_internal(&k-kobj);15. if(err)16. returnerr;17. /*事件相关*/18. kobject_uevent(&k-kobj,KOBJ_ADD);19. return0;20. cpp view plaincopyprint?1. /*2. *kset_register-initializeandaddakset.3. *k:kset.4. */5. intkset_register(structkset*k)6. 7. interr;8. 9. if(!k)10. return-EINVAL;11. /*基本的初始化*/12. kset_init(k);13. /*kobj以及其属性建立sd树*/14. err=kobject_add_internal(&k-kobj);15. if(err)16. returnerr;17. /*事件相关*/18. kobject_uevent(&k-kobj,KOBJ_ADD);19. return0;20. /* * kset_register - initialize and add a kset. * k: kset. */int kset_register(struct kset *k)int err;if (!k)return -EINVAL;/*基本的初始化*/kset_init(k);/*kobj以及其属性建立sd树*/err = kobject_add_internal(&k-kobj);if (err)return err;/*事件相关*/kobject_uevent(&k-kobj, KOBJ_ADD);return 0;kset初始化cpp view plaincopyprint?1. /*2. *kset_init-initializeaksetforuse3. *k:kset4. */5. voidkset_init(structkset*k)6. 7. /*kobject结构初始化*/8. kobject_init_internal(&k-kobj);9. /*初始化kset的kobject链表*/10. INIT_LIST_HEAD(&k-list);11. spin_lock_init(&k-list_lock);12. cpp view plaincopyprint?1. /*2. *kset_init-initializeaksetforuse3. *k:kset4. */5. voidkset_init(structkset*k)6. 7. /*kobject结构初始化*/8. kobject_init_internal(&k-kobj);9. /*初始化kset的kobject链表*/10. INIT_LIST_HEAD(&k-list);11. spin_lock_init(&k-list_lock);12. /* * kset_init - initialize a kset for use * k: kset */void kset_init(struct kset *k)/*kobject结构初始化*/kobject_init_internal(&k-kobj);/*初始化kset的kobject链表*/INIT_LIST_HEAD(&k-list);spin_lock_init(&k-list_lock);cpp view plaincopyprint?1. staticvoidkobject_init_internal(structkobject*kobj)2. 3. if(!kobj)4. return;5. kref_init(&kobj-kref);/*引用计数加一*/6. INIT_LIST_HEAD(&kobj-entry);/*初始化链表*/7. kobj-state_in_sysfs=0;8. kobj-state_add_uevent_sent=0;9. kobj-state_remove_uevent_sent=0;10. kobj-state_initialized=1;/*已经初始化*/11. cpp view plaincopyprint?1. staticvoidkobject_init_internal(structkobject*kobj)2. 3. if(!kobj)4. return;5. kref_init(&kobj-kref);/*引用计数加一*/6. INIT_LIST_HEAD(&kobj-entry);/*初始化链表*/7. kobj-state_in_sysfs=0;8. kobj-state_add_uevent_sent=0;9. kobj-state_remove_uevent_sent=0;10. kobj-state_initialized=1;/*已经初始化*/11. static void kobject_init_internal(struct kobject *kobj)if (!kobj)return;kref_init(&kobj-kref);/*引用计数加一*/INIT_LIST_HEAD(&kobj-entry);/*初始化链表*/kobj-state_in_sysfs = 0;kobj-state_add_uevent_sent = 0;kobj-state_remove_uevent_sent = 0;kobj-state_initialized = 1;/*已经初始化*/建立sd树cpp view plaincopyprint?1. staticintkobject_add_internal(structkobject*kobj)2. 3. interror=0;4. structkobject*parent;5. 6. if(!kobj)7. return-ENOENT;8. 9. if(!kobj-name|!kobj-name0)10. WARN(1,kobject:(%p):attemptedtoberegisteredwithempty11. name!n,kobj);12. return-EINVAL;13. 14. /*如果kobj的parent存在,增加其引用计数*/15. parent=kobject_get(kobj-parent);16. 17. /*joinksetifset,useitasparentifwedonotalreadyhaveone*/18. if(kobj-kset)19. if(!parent)/*如果其parent不存在,那么用kset中的kobject作为20. 其parent,这里可以看出kset-kobj的parent为自身*/21. parent=kobject_get(&kobj-kset-kobj);22. kobj_kset

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论