翼度科技»论坛 云主机 LINUX 查看内容

linux进阶:设备驱动模型

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24
为什么需要设备驱动模型

内核版本发展

2.4版本之前内核没有统一的设备驱动模型,但是可以用(例如先前的led字符设备驱动实验,使用前需要手动调用mknod命令创建设备文件,从而进一步控制硬件)。
2.4~2.6版本内核使用devfs,挂载在/dev目录。需要在内核驱动中创建设备文件(调用devfs_register创建设备文件,无需手动mknod命令,需传入设备文件名),命名过于死板(编译后驱动对应的设备文件名固定,无法动态修改)。
2.6版本之后内核统一使用sysfs,挂载在/sys目录。将设备分类、分层次统一进行管理,配合udev/mdev守护进程(开启自启,后台运行,一直监听内核驱动发出的消息)动态创建设备文件,命令规则自由制定。
sysfs虚拟文件系统在linux系统中体现出设备驱动模型,类似于proc文件系统,总是被挂载在/sys/挂载点上。目录对应的inode节点会记录基本驱动对象(kobject),从而将系统中的设备组成层次结构。用户可以读写目录下的不同文件来配置基本驱动对象(kobject)的不同属性。
 
设备(device):挂载在某个总线的物理设备。
驱动(driver):与特定设备相关的软件,负责初始化该设备以及提供一些操作该设备的操作方式。
总线(bus):负责管理挂载对应总线的设备以及驱动。
类(class):对于具有相同功能的设备,归结到一种类别,进行分类管理。
 
/sys文件目录记录着各个设备之间的关系。
/sys/bus是按照总线类型分层放置的目录结构,目录下的每个子目录都是已经注册的总线类型。每个子目录(总线类型)包含:devices文件夹drivers文件夹。devices文件夹下是该总线类型的所有设备(里的所有设备都是符号链接,分别指向真正的设备/sys/devices/)。drivers文件夹下是所有注册在这个总线上的驱动(每个driver子目录下是一些可以观察和修改的driver参数)。
/sys/devices目录下是全局设备结构体系,包含所有被发现的注册在各种总线上的各种物理设备。一般来说,所有的物理设备都按其在总线上的拓扑结构来显示。
/sys/class是按照设备功能分类的设备模型,目录下包含所有已经注册在内核的设备类型。
 
设备驱动模型基本元素

kobject:sysfs的一个目录,常用来表示基本驱动对象,不允许发送消息到用户空间。
kset:sysfs的一个目录,常用来管理kobject,允许发送消息到用户空间。
kobj_type:目录下属性文件的操作接口。
kobject既可以通过parent指针找到上层kobject,也可以通过kset指针找到上层kobject。但上层kobject对象无法遍历到下层,所以较少使用。
 
kobject结构体

sysfs中每一个目录都对应一个kobject,kobject结构体存放在内核/include/linux/kobject.h。
  1. struct kobject {
  2.         const char              *name;        //kobject的名称,同时也是sysfs下的目录名字
  3.         struct list_head        entry;        //链表节点,用于将kobject加入到kset的list_head
  4.         struct kobject          *parent;    //该kobject的上层节点,构建kobject间的层次关系(在sysfs体现为目录结构)
  5.         struct kset             *kset;        //该kobject所属的kset对象(可以为NULL),用于批量管理kobject对象
  6.         struct kobj_type        *ktype;        //该kobject的sysfs文件系统相关的操作和属性
  7.         struct kernfs_node      *sd;         //该kobject在sysfs文件系统中对应目录项
  8.         struct kref             kref;        //该kobject的引用次数
  9. #ifdef CONFIG_DEBUG_KOBJECT_RELEASE
  10.         struct delayed_work     release;
  11. #endif
  12.         unsigned int state_initialized:1;            //记录内核对象的初始化状态
  13.         unsigned int state_in_sysfs:1;                //表示该kobject所代表的内核对象是否在sysfs建立目录
  14.         unsigned int state_add_uevent_sent:1;        //记录是否已经向用户空间发送ADD uevent事件
  15.         unsigned int state_remove_uevent_sent:1;    //记录是否已经向用户空间发送REMOVE uevent事件
  16.         unsigned int uevent_suppress:1;                //如果为1,则忽略所有上报的uevent事件
  17. };
复制代码
由于kobject添加到内核时,需要根据名字注册到sysfs虚拟文件系统中,之后就不能再直接修改该名字。如果想改,需要调用kobject_rename接口,该接口会主动处理sysfs的相关事宜。
kset如果没有指定的parent,则会把kset作为parent(kset是一个特殊的kobject)。
uevent提供了“用空空间通知”的功能实现,当内核中有kobject的增删改等操作时,会通知用户空间。
 
kset结构体

kset结构体存放在内核/include/linux/kobject.h。
  1. struct kset {
  2.         struct list_head list;                        //指向该kset下所有的kobject组成的链表
  3.         spinlock_t list_lock;                        //避免操作链表时产生竞态的自旋锁
  4.         struct kobject kobj;                        //该kset自己的kobject(kset是一个特殊的kobject,也会在sysfs中以目录的形式体现)
  5.         const struct kset_uevent_ops *uevent_ops;   
  6. } __randomize_layout;
复制代码
uevent_ops为该kset的uevent操作函数集(函数指针)。当kset的某些kobject对象发生状态变化需要通知用户空间时,调用其中对应的函数来完成。
当任一kobject需要上报uevent时,都要调用它所属的kset的uevent_ops,添加环境变量,或者过滤uevent(kset可以决定哪些uevent可以上报)。
因此一个kobject不属于任一kset时,是不允许发生uevent的。
 
kobj_type结构体

kobj_type结构体存放在内核/include/linux/kobject.h。
  1. struct kobj_type {
  2.         /* 销毁kobject对象时调用 */
  3.         void (*release)(struct kobject *kobj);
  4.         
  5.         /* 该类型的kobject的sysfs虚拟文件系统操作接口(读属性接口show和写属性接口store) */
  6.         const struct sysfs_ops *sysfs_ops;
  7.         
  8.         /* 该类型的kobject的attribute表(sysfs的一个文件)。将会在kobject添加到内核时,一并注册到sysfs中 */
  9.         struct attribute **default_attrs;
  10.         
  11.         const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
  12.         const void *(*namespace)(struct kobject *kobj);
  13.         void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid);
  14. };
复制代码
 
 
kobject:驱动的基石

步骤


  • 创建一个kobject对象
  • 创建一个sysfs的目录项(kernfs_node)
  • 把它们关联起来
 
重点


  • 关注sysfs目录项与kobject对象的关联过程
  • 关注kobject对象默认的属性文件操作接口
 
kobject主要提供如下功能:

  • 通过parent指针,可以将所有kobject以层次结构的形式组合起来。
  • 使用一个引用计数,来记录kobject被引用的次数,并在引用计数为0时释放kobject对象(这是kobject诞生时的唯一功能)。
  • 和sysfs虚拟文件系统配合,将每一个kobject及其特性以文件形式显示到用户空间。
  • 在Linux中,kobject几乎不会单独存在。它的主要功能就是内嵌在一个大型的数据结构中,为这个数据结构提供一些底层的功能实现。
  • Linux驱动开发者很少会直接使用kobject以及它提供的接口,而是使用构建在kobject之上的设备模型接口。
 
kobject_create_and_add()函数

存放在内核/lib/kobject.c
  1. struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
  2. {
  3.         struct kobject *kobj;
  4.         int retval;
  5.         kobj = kobject_create();                            //创建并初始化一个kobject对象
  6.         if (!kobj)
  7.                 return NULL;
  8.         retval = kobject_add(kobj, parent, "%s", name);        //sysfs创建一个目录项并与kobject对象关联
  9.         if (retval) {
  10.                 pr_warn("%s: kobject_add error: %d\n", __func__, retval);
  11.                 kobject_put(kobj);
  12.                 kobj = NULL;
  13.         }
  14.         return kobj;
  15. }
复制代码
kobject_create_and_add()函数是kobject_create函数和kobject_add函数的组合。整体功能是创建一个名字为“name”的kobject对象,并将其添加到指定的父kobject对象下。
 

来源:https://www.cnblogs.com/couvrir/p/17635705.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具