一、为什么需要设备驱动模型
早期内核(2.4之前)没有统一的设备驱动模型,但照样可以用。需要手动调用 mknod
指令创建设备文件,绑定了 file_operation 后才能调用驱动控制硬件,很不方便。
2.4~2.6期间使用devfs,就是设备文件系统,挂载在/dev目录。
需要在内核驱动中创建设备文件(devfs_register,参数为设备文件名),不再需要手动使用 mknod
指令来创建设备文件。
但这种方式命名死板。
2.6以后使用sysfs,挂载在/sys目录下。
将设备分类、分层统一进行管理。
配合 udev / mdev 守护进程动态创建设备文件,命令规则自由制定。
二、sysfs概述
linux系统通过sysfs体现出设备驱动模型。
sysfs是一个 虚拟文件系统
(类似proc文件系统)。一个用来体现设备驱动模型(上面的分类和层次关系),一个用来展示进程方面的相关消息。
目录 对应的 inode节点 会记录基本驱动对象(kobject),从而将系统中的设备组成层次结构。
一个kobject对象 与 sysfs中的一个目录 对应。
linux把目录也抽象成inode节点:普通文件的inode节点就是用来记录这个文件的内容;目录节点用来记录这个目录下面的所有文件的相关信息。
所有的复杂的设备都会继承这个 kobject 对象。struct cdev 也继承了 struct kobject。
用户可以读写kobject对应的目录下的不同文件来配置驱动对象(kobject)的不同属性。
三、设备驱动模型3个基本元素
kobject:sysfs中的一个目录,常用来表示基本驱动对象,不允许发送消息到用户空间。守护进程udev 或者 守护进程mdev 会监控驱动程序发出来的消息。kobject不允许发送消息给 udev 或 mdev。
kset:sysfs中的一个目录,常用来管理 kobject 或者 另一个 kset,允许发送消息到用户空间。
kobj_type:一个kobject对应一个目录,这个目录下属性文件的操作接口。
1、kobject
sysfs中每一个目录都对应一个kobject
include/linux/kobject.h
struct kobject {
//用来表示该 kobject 的名称,sysfs 目录下的目录名称。
const char *name;
//链表节点,将 kobject 串联起来进行管理。
struct list_head entry;
//该 kobject 的上层节点,构建 kobject 之间的层次关系。
struct kobject *parent;
//该 kobject 所属的 kset 对象,kset对象 用于批量管理 kobject 对象。
struct kset *kset;
//该 kobject 的 sysfs 文件系统相关的操作和属性接口。下面有详细介绍。
struct kobj_type *ktype;
//指向该 kobject 在 sysfs 文件系统中对应目录项。由此实现一个kobject对应一个目录。
struct kernfs_node *sd; /* sysfs directory entry */
//该 kobject 的引用次数。
struct kref kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
//记录内核对象 kobject 的初始化状态,赋1表示已经初始化。
unsigned int state_initialized:1;
//表示该 kobject 所代表的内核对象有没有在 sysfs 建立相应目录,赋1表示建立了目录。
unsigned int state_in_sysfs:1;
//下面3个适合发送消息到用户空间相关。
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
2、kset
struct kset {
//链表头,用来将管理的 kobject 对象构建成链表
struct list_head list;
//自旋锁,确保 kset 的互斥访问。
spinlock_t list_lock;
//当前kset内核对象继承的 kobject 对象。
struct kobject kobj;
//定义了一组函数指针,当kset中的某些kobject对象发生状态变化需要通知用户空间时,调用其中的函数来完成。
const struct kset_uevent_ops *uevent_ops;
}
3、kobj_type
用来记录 kobject 对象关联的 sysfs下的目录 下面的文件操作接口。
struct kobj_type {
//销毁 kobject 对象时调用
void (*release)(struct kobject *kobj);
//kobject对象属性文件统一操作接口,重点关注
const struct sysfs_ops *sysfs_ops;
//kobject默认属性文件的名字、"文件具体操作接口",重点关注
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
};
四、两种驱动模型
1、驱动模型一
kset 会继承一个kobject。
子kset的kobject成员的parent节点 会设置为 父kset的kobject成员。
利用 parent指针 来体现层次关系。
kobject 的 kset指针指向 管理它的 kset。
kset可批量管理kobject
kobject无法批量管理kobject
2、驱动模型二
此时下层的 kobject 可以找到上层的 kobject;但是此时上层的kobject 无法找到 下层的kobject(不像上面的kset包含一个链表头)。
所以此模型虽然简单但是很少用。