linux26内核模型.pdf
《linux26内核模型.pdf》由会员分享,可在线阅读,更多相关《linux26内核模型.pdf(20页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、 Linux 2.6 Device Model v1.0 By semiyd 2007/7/26 Linux2.6 的设备模型是一个复杂的数据结构体系,不能用一种简单形象的结构来进行整体的描述。本文试图用一些易于理解的方式,解释这个体系的构造。总体上,会偏向与driver 的相关内容,与 driver 不太相干的东东会相应的忽略,并且侧重对体系结构的理解,对 device model 中的很多技术细节就不去一一解释了,具体可以看linux 设备驱动程序中的相关章节。全文分为 2 大部分。第一部分是解释整个体系结构。第二部分是结合具体的驱动的内核注册过程,看一下体系的工作流程。Part One:
2、The Device Model 在介绍这个体系之前,先要说明一下下列一些重要的概念。Kobject Kset Subsystem Sysfs Bus Device Class Device_driver KOBJECT kobject 是设备模型中的基本的结构。从代码上看,是一个结构体。但是 linux 中引入了面向对象的思想,从某些角度,也可以看成是一个类。struct kobject const char *k_name;/name of the kobject char nameKOBJ_NAME_LEN;struct kref kref;/reference counting(引用计
3、数)struct list_head entry;struct kobject *parent;/父类 struct kset *kset;struct kobj_type*ktype;struct dentry *dentry;wait_queue_head_t poll;kobject 对象通常被嵌入到其他的结构中。从面向对象的观点看,kobject 可以看成是基类,而其他类都是派生的产物。这一点在后面的图表中会有具体的说明。不过这里还是举一个派生的例子:device_driver。struct device_driver const char *name;struct bus_type
4、*bus;struct completion unloaded;struct kobject kobj;struct klist klist_devices;struct klist_node knode_bus;struct module *owner;int(*probe)(struct device*dev);int(*remove)(struct device*dev);void(*shutdown)(struct device*dev);int(*suspend)(struct device*dev,pm_message_t state);int(*resume)(struct de
5、vice*dev);各种操作:void kobject_init(struct kobject*);初始化 int kobject_add(struct kobject*);加入 kset 并且在 sysfs 中显示 kobject。kobject 不一定会在不一定会在 sysfs 里显示,除非你调用了这个函数。里显示,除非你调用了这个函数。int kobject_register(struct kobject*);kobject_init 和 kobject_add 的简单结合 void kobject_del(struct kobject*);void kobject_unregister
6、(struct kobject*);struct kobject*kobject_get(struct kobject*);增加引用计数 void kobject_put(struct kobject*);减少引用计数 kobject 的一个重要函数是为他的结构设置引用计数(reference counting)。只要对象的引用计数存在,对象(以及支持他的代码)就必须存在。KSET 一个 kset 是相同类型的 kobject 的一个集合。这里所说的类型,是有一个叫kobj_type 类型的指针来描述的。kset 一定会在一定会在 sysfs 里显示出来。里显示出来。我们可以认为,他是kobj
7、ect 的顶层容器(container)类。在每个 kset 的内部,包含了自己的 kobject,并且可以用多种处理 kobject 的方法处理 kset。struct kset struct subsystem*subsys;struct kobj_type*ktype;struct list_head list;spinlock_t list_lock;struct kobject kobj;struct kset_uevent_ops*uevent_ops;struct kobj_type void(*release)(struct kobject*);struct sysfs_ops
8、*sysfs_ops;struct attribute*default_attrs;不过这里的 kset 还不一定是顶部的,也就是说,在同属于相同的 kobj_type 类型下,他有可能是另外一个 kset 的一部分。操作:void kset_init(struct kset*k);int kset_add(struct kset*k);int kset_register(struct kset*k);void kset_unregister(struct kset*k);static inline struct kset*kset_get(struct kset*k)/改动引用计数 stat
9、ic inline void kset_put(struct kset*k)/改动引用计数 SUBSYSTEM 子系统通常就是整个体系的顶层结构。在 sysfs 中,显示为/sys 下面的第一级目录。下面就来看看,通常/sys 下面的目录结构:block/bus/class/devices/firmware/net/fs/这里,就可以看见诸如 class(相当于 struct class)之类的子系统。struct subsystem struct kset kset;struct rw_semaphore rwsem;/用于串行访问 kset 内部的链表的信号量;在看刚刚的 class 例子
10、 struct class const char *name;struct module *owner;struct subsystem subsys;struct list_head children;struct list_head devices;struct list_head interfaces;struct semaphore sem;/*locks both the children and interfaces lists*/struct class_attribute *class_attrs;struct class_device_attribute*class_dev_
11、attrs;int(*uevent)(struct class_device*dev,char*envp,int num_envp,char*buffer,int buffer_size);void(*release)(struct class_device*dev);void(*class_release)(struct class*class);其实从定义上可以看出,子系统就是对一个 kset 和一个信号量的封装。操作:extern void subsystem_init(struct subsystem*);extern int subsystem_register(struct sub
12、system*);extern void subsystem_unregister(struct subsystem*);但驱动程序的编写人员是不会用到 subsys 级别的初始化之类的调用的。SYSFS sysfs 是一种基于内存的文件结构。简单的说,就是为内核的数据结构,一些属性,符号链接提供一个在用户空间中显示和交互的方式。在系统里,显示为/sys 文件夹。mount-t sysfs/sys 就可以在文件系统里看见/sys 的目录了。每一个在 kernel 里面注册的 kobject,在/sys 里面都会产生一个相应的目录,名字就 kobject 的 name。那么如果这个 kobjec
13、t 有父类的话,那它对应的目录就会成为父类的子目录,这样就可以反映 kobject 的继承关系。下面是/sys 下一级目录的结构。block/bus/class/devices/firmware/net/fs/这里要提一个叫 attribute 的概念,也就是属性。attribute 是 kobject 里面的东西。在 sysfs 中,属性能够以常规的文件的形式,输出到 sysfs 的目录当中。并且,当 kobject的属性提供了读写的方法,sysfs 中就可以对相应的文件进行读写,从而访问 kobject 里面的一些信息。具体在 kobject 里面,有 kobj_type 结构:struc
14、t kobj_type void(*release)(struct kobject*);struct sysfs_ops*sysfs_ops;struct attribute*default_attrs;struct attribute const char *name;struct module *owner;mode_t mode;attribute 用于保存属性列表。*name 就是属性名了,也就是 sysfs 里面的文件名。mode 是保护位,如果是只读,就要设置成 S_IRUGO,读写就是 S_IWUSR。struct sysfs_ops ssize_t(*show)(struct
15、kobject*,struct attribute*,char*);/读 ssize_t(*store)(struct kobject*,struct attribute*,const char*,size_t);/写;sysfs_ops 就是具体怎么实现在用户空间/sys 下面的读写操作了。另外,如果希望在 kobject 的 sysfs 目录中添加新的属性,只需要填写一个 attribute 结构体,然后调用下面的函数:sysfs_create_file(struct kobject*kobj,const struct attribute*attr)如果把 attribute 看成一个基类
16、的,那这里有一个衍生的类,叫 device_attribute:struct device_attribute struct attribute attr;ssize_t(*show)(struct device*dev,char*buf);ssize_t(*store)(struct device*dev,const char*buf);相应的,也有函数来添加新属性:int device_create_file(struct device*,struct device_attribute*);void device_remove_file(struct device*,struct devi
17、ce_attribute*);同理有 driver_attribute。最后要说的就是符号链接。sysfs 具有树形的结构,来反映 kobject 之间的组织关系。但内核中的对象之间的关系远比这个复杂。比如,/sys/devices 的树表示了所有的设备,/sys/bus 的树可以表示设备的驱动。但驱动和设备之间的关系又如何表示呢?这里就需要一个指针,叫符号链接(symlink)来表示这种联系。int sysfs_create_link(struct kobject*kobj,struct kobject*target,const char*name)函数创建了一个叫 name 的链接,指向
18、target 的 sysfs 入口,并作为 kobj 的一个属性。到目前为止,介绍了 device model 的底层部分。下面,将讲述设备模型的上层部分。BUS 在设备模型中,所有的 device 都通过 bus 相连。这里的 bus 包括通常意义的总线,也包括虚拟的 platform 总线,下面会有具体的说明。总线可以互相插入,比如,usb host可以是 pci device。bus_type 结构表示了总线:struct bus_type const char *name;struct subsystem subsys;struct kset drivers;struct kset d
19、evices;struct klist klist_devices;struct klist klist_drivers;struct bus_attribute*bus_attrs;struct device_attribute*dev_attrs;struct driver_attribute*drv_attrs;int (*match)(struct device*dev,struct device_driver*drv);int (*uevent)(struct device*dev,char*envp,int num_envp,char*buffer,int buffer_size)
20、;int (*probe)(struct device*dev);int (*remove)(struct device*dev);void (*shutdown)(struct device*dev);int (*suspend)(struct device*dev,pm_message_t state);int (*resume)(struct device*dev);name 是总线的名字。从上面的定义可以看到,每个总线都有自己的子系统,这些子系统并不是指 sysfs 顶层的那个 subsystem。另外包含 2 个 kset。分别代表总线的 device 和 driver。后面可以看到
21、,sysfs 中,每种总线下面,总有 device 和 driver 2 个文件夹。下面举个例子,说明一下 pci 总线的声明。struct bus_type pci_bus_type=.name=pci,.match=pci_bus_match,;值得注意的是,只有很少的 bus_type 成员需要初始化;大部分都可以交给 kernel 处理。有关总线的操作函数,这里仅仅介绍一个常用的:int bus_for_each_dev(struct bus_type*bus,struct device*start,void*data,int(*fn)(struct device*,void*)str
22、uct klist_iter i;struct device*dev;int error=0;if(!bus)return-EINVAL;klist_iter_init_node(&bus-klist_devices,&i,(start?&start-knode_bus:NULL);while(dev=next_device(&i)&!error)error=fn(dev,data);klist_iter_exit(&i);return error;他的作用是遍历 bus 上的 device,并进行 fn 操作。通常的用途是:绑定设备和驱动:void driver_attach(struct
23、device_driver*drv)bus_for_each_dev(drv-bus,NULL,drv,_driver_attach);static int _driver_attach(struct device*dev,void*data)struct device_driver*drv=data;/*Lock device and try to bind to it.We drop the error *here and always return 0,because we need to keep trying *to bind to devices and some drivers
24、will return an error *simply if it didnt support the device.*driver_probe_device()will spit a warning if there *is an error.*/if(dev-parent)/*Needed for USB*/down(&dev-parent-sem);down(&dev-sem);if(!dev-driver)driver_probe_device(drv,dev);up(&dev-sem);if(dev-parent)up(&dev-parent-sem);return 0;几乎在几乎
25、在 linux 设备模型的每一层都提供了添加属性的函数设备模型的每一层都提供了添加属性的函数,总线也不例外。struct bus_attribute struct attribute attr;ssize_t(*show)(struct bus_type*,char*buf);ssize_t(*store)(struct bus_type*,const char*buf,size_t count);下面说明一下 bus 在 sysfs 里面的结构。刚刚已经提到了,由于有 2 个 kset,那么每个bus 都会有 driver 和 device2 个文件夹。具体的说:每个在总线上注册过的驱动都会
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux26 内核 模型
限制150内