1.设备文件系统(devfs)
1.1在设备初始化时在/dev目录下创建设备文件,卸载时把它删除
1.2设备驱动程序可以指定设备名,所有者和权限,用户空间中可以修改
1.3不需要分配主设备号以及次设备号,直接可以给register_chrdev()传递0主设备号可以动态获取可用的主设备号,并在devfs_register()中指定次设备号。头文件:linux/devfs_fs_kernel.h
devfs_handle_t devfs_mk_dir(devfs_handle_t dir,const char *name ,void *info);//创建设备目录
devfs_handle_t devfs_register(devfs_handle_t dir,const char *name ,unsigned int flags,unsigned int major,unsigned int minor,umode_t mode,void *opos,void *info);//创建设备文件
void devfs_unregister(devfs_handle_t de);//撤销设备文件
1.udev与devfs的区别
尽管devfs有那些优点,但是在linux2.6内核中,devfs被认为是过时的方法,使用udev去带了devfs的几点原因:
①devfs 所做的工作被确信可以在用户态来完成。
②一些 bug 相当长的时间内未被修复。
③devfs 的维护者和作者停止了对代码的维护工作
udev 完全在用户态工作,利用设备加入或移除时内核所发送的热插拔事件(hotplugevent) 来工作。在热插拔时,设备的详细信息会由内核输出到位于/sys 的 sysfs 文件系统。
udev 的设备命名策略、 权限控制和事件处理都是在用户态下完成的, 它利用 sysfs 中的信息来进行创建设备文件节点等工作。
由于 udev 根据系统中硬件设备的状态动态更新设备文件, 进行设备文件的创建和删除等,因此,在使用 udev 后,/dev 目录下就会只包含系统中真正存在的设备了。
devfs 与 udev 的另一个显著区别在于:采用 devfs,当一个并不存在的/dev 节点被打开的时候,devfs 能自动加载对应的驱动,而 udev 则不能。这是因为 udev 的设计者认为 Linux 应该在设备被发现的时候加载驱动模块,而不是当它被访问的时候。udev的设计者认为 devfs 所提供的打开/dev 节点时自动加载驱动的功能对于一个配置正确的计算机是多余的。系统中所有的设备都应该产生热插拔事件并加载恰当的驱动,而udev 能注意到这点并且为它创建对应的设备节点。
sysfs 把连接在系统上的设备和总线组织成为一个分级的文件, 它们可以由用户空间存取, 向用户空间导出内核数据结构以及它们的属性。 sysfs 的一个目的就是展示设备驱动模型中各组件的层次关系,其顶级目录包括
①block:包含所有的块设备
②device:包含系统所有的设备并根据设备挂接的总线类型组织成层次结构
③bus:包含系统中所有的总线类型
④drivers:包含内核中所有的已注册的设备驱动程序
⑤class:包含系统中的设备类型
⑥power和 firmware
3.kobject内核对象:是所有设备在底层都有统一的接口
struct kobject{
char *k_name;
char name[KOBJ_NAME_LEN];//对象名称
struct kref kref;//对象引用计数
//kobject_get(),kobject_put()分别用于增加和减少引用计数,当引用计数为零,所有该以对象使用资源被释放
struct list_head entry;//挂接kobject到kset链表
struct kobject *parent;//指向父对象指针
struct kset *kset;//所属kset对象
struct kobj_type *ktype;//对象类型描述符指针
struct dentry *dentry;//sysfs文件系统对象对应的文件节点入口
};
struct kobj_type{
void (*release)(struct kobjct *);//release函数
struct sysfs_ops *sysfs_ops;//属性操作、
struct attribute ** default_attrs;//默认属性
};
kobj_type 数据结构包含 3 个成员:用于释放 kobject 占用的资源的
release()函数、指向 sysfs 操作的 sysfs_ops 指针和 sysfs 文件系统默认属性列表
kobj_type 结构体种的 sysfs_ops 包括 store()和 show()两个成员函数,用于实现属
性的读写。
1.当从用户空间读取属性时,show()函数将被调用,该函数将指定属性值存入 buffer 中返回给用户
2.store()函数用于存储用户通过 buffer 传入的属性值。
void kobject_init(struct kobject * kobj);
//该函数用于初始化 kobject,它设置 kobject 引用计数为1,entry 域指向自身,其所属 kset 引用计数加 1。
-------------------------------------------------------------------
int kobject_set_name(struct kobject *kobj, const char *format, ...);
//该函数用于设置指定 kobject 的名称。
-------------------------------------------------------------------
Void kobject_cleanup(struct kobject * kobj) 和
void kobject_release(struct kref *kref);
//该函数用于清除 kobject,当其引用计数为0时,释放对象占用的资源。
-------------------------------------------------------------------
struct kobject *kobject_get(struct kobject *kobj);
//该函数用于将 kobj 对象的引用计数加 1,同时返回该对象的指针。
-------------------------------------------------------------------
void kobject_put(struct kobject * kobj);
//该函数用于将kobj对象的引用计数减1,如果引用计数降为0, 则调kobject_release()释放该 kobject对象。
-------------------------------------------------------------------
int kobject_add(struct kobject * kobj);
//该函数用于将 kobject 对象加入 Linux 设备层次,它会挂接该 kobject 对象到 kset的 list 链中,增加父目录各级 kobject 的引用计数,在其 parent 指向的目录下创建文件节点,并启动该类型内核对象的 hotplug 函数
-------------------------------------------------------------------
void kobject_del(struct kobject * kobj);
//这个函数是 kobject_add()的反函数, 它从 Linux 设备层次(hierarchy)中删除 kobject
对象。
-------------------------------------------------------------------
int kobject_register(struct kobject * kobj);
//该函数用于注册 kobject,它会先调用 kobject_init()初始化 kobj,再调用kobject_add()完成该内核对象的添加
-------------------------------------------------------------------
void kobject_unregister(struct kobject * kobj);
//这个函数是 kobject_register()的反函数,用于注销 kobject。与kobject_register()相反,它首先调用 kobject_del()从设备层次中删除该对象,再调用 kobject_put()减少该对象的引用计数,如果引用计数降为 0,则释放该 kobject 对象。
4.kset 内核对象集合:是具有相同类型的kobject 的集合
struct kset{
struct subsystem * subsys;//子系统的指针
struct kobj_type *ktype;//kset对象描述指针
struct list_head list;
spinlock_t list_lock;
struct kobject kobj; //嵌入的 kobject
struct kset_uevent_ops * uevent_ops;//事件操作集
};