linux设备驱动模型由大量的数据结构与算法组成,这里面关系很复杂,结构和结构之间一般使用指针连接。
构成树或网状结构。而描述这种结构的最好的方法是利用一种树形的一些文件系统。
linux设备驱动模型中的肯定是要挂载设备信息,驱动和总线信息的,所以这种文件系统肯定是要和其他类型的文件系统不一样,要有自己的特殊之处(ext2用于快速读写存储文件,ext3用于记录日志文件),正是因为有着不同之处,才被称为sysfs
| Linux内核中的结构 | sysfs中的结构 |
|---|---|
| kobject | 目录 |
| kobj_type | 属性文件 |
| 对象之间的关系 | 符号链接 |

设备驱动模型是一个层次化的结构,在内核中就通过kobject,kset,subsystem这几个结构体描述。这种层次化的结构可以将驱动,设备,总线等联系起来。
一般来说我们可以用这样的树形结构去表示设备驱动模型中dev/drv/bus组成层次结构:

这个结构在sysfs文件系统中将会以这样形式存在:
这节的主角kobject与就与下面的目录一一对应,kobject里描述了目录的组织结构和名字

kobject结构体是组成驱动模型的基本结构
每一个在内核中注册的kobject对象都对应于sysfs文件系统中的一个目录
kobject的结构体如下:(include/linux/kobject.h)
64行 name存储kobject结构体名称,该名称对应着目录的名字
65行 list_head和第二节中cdev结构体里的是用一个结构体,用于连接下一个kobject结构
66行 parent变量用于连接其父目录所代表的kobject结构体
67行 kset用于组成层次化的结构,他是具有想同类型的kobject集合 后面会详细说
68行 kobj_type用于指向kobject的类型描述符,代表kobject属性,对应着sysfs中的一个属性文件
69行 sd对应sysfs的文件目录
70行 kref为kobject的引用计数
74行 state_initialized用位域表示该kobject是否被初始化过
75行 state_in_sysfs表示是否注册进sysfs文件系统

首先应使用memset函数将kobject置0
然后调用kobject_init():
源码如下(\linux-4.9.229\arch\powerpc\platforms\powernv\opal-dump.c)
首先是两个检查:
检查传入的kobj ktype指针是否指向空
再检查kobj是否被初始化
随后调用kobject_init_internal
最后使用传入的ktype初始化kobject的ktype

kobject_init_internal源码:(lib\kobject.c)
这个函数主要是对kobject进行初始化:
kref引用计数初始化
并且初始化kobj的entry指针,这里面其实就是初始化一个双向链表(数据结构知识)
并标记kobject还没有注册到sysfs文件系统
设置该结构体已经被初始化过了

对于kref值的引用计数控制
增加kref的计数使用kobject_get(内部调用kref_get)
减少kref的计数使用kobject_put(内部调用kref_put)
源码和英文注释如下:


可以在kref_put的参数列表里发现release函数
这是个回调函数,kobject引用计数为0的时候,需要释放kobject对象和其占用的资源,无法做一个单独的函数作为释放函数,因为每个设备所用资源都是不一样的,所以就需要驱动开发程序员去自己实现释放资源函数
这个释放函数会在资源引用数为0时被系统自动调用。
kobj_type对应sysfs文件系统里的属性文件,指代设备的一些属性
一开始kobj_type结构只是放在kobject结构中的成员
后来发现这个东西可以复用,因为同一类设备,会有相同的属性,创建每个kobject都要重复创建type实在太麻烦
所以就把它单独做了个结构体:(include/linux/kobject.h)

进行到此刻可以先纵观一下Kobject与kobj_type之间的关系:
kobject包含ktype指针,初始化时要将ktype指针指向初始化好的ktype结构体
kobject中的parent指针
ktype结构体里面三个重要的release, sysfs_ops , attribute结构体
release需要程序员自己实现的资源释放函数
sysfs_ops表示对属性操作的函数
attribute表示属相集合
一个kobject可以有多个ktype即一个目录下可以有多个属性文件