LINUX设备驱动模型分析之 CLASS相关接口分析
前面已经介绍了总线、设备、驱动,本章主要介绍设备类,该模块主要对系统中的设备进行分类,而该设备类主要是用于将系统中已创建的设备归到各自类型中,而CLASS中各类别主要是对device的链接。下面是我的电脑中已注册的设备类别。

我们以block类为例,其目录下所有子目录均是对/sys/devices中的设备的链接。

此处我们将从class相关的结构体、class模块初始化、class类别的注册与注销、class设备的添加与删除这几部分进行分析。
class相关的结构体
class结构体的定义如下,其实和bus_type的定义类似,class通过包含subsys_private类型的变量,也就包含了subsystem,其中也定义了kset类型的subsys变量,用于将该类下所有的设备关联在一起等。

class模块初始化
该模块的初始化主要用于创建class类别的全局kset变量,通过调用kset_create_and_add接口即完成了创建kset变量以及其对应的kobject变量,同时在sysfs文件系统的根目录下创建了名为class的目录,即为此在sysfs目录下完成class类别的创建。
int __init classes_init(void)
{
class_kset = kset_create_and_add("class", NULL, NULL);
if (!class_kset)
return -ENOMEM;
return 0;
}
而针对class_kset而言,其主要用于将所有注册到系统中的类别对应的kobject链接至一起。当系统中注册了多个类别后,则class与class_kset的关联如下图所示。

class类型的注册与注销
class类型的注册
针对具体类型的class的注册,也就是完成class_kset、class_attr、kobject、sysfs、device等几个模块间变量的关联,这些变量的关联如下流程图所示,主要也就是包括如下几个方面:
- 将创建的class类型对应的kobject链接至class_kset;
- 调用kset_register接口,为该class的kset进行注册(主要是完成在sysfs的/sys/class目录下创建对应的目录,也即创建sysfs_dirent变量),同时调用add_class_attrs,为该class变量创建默认的属性,即创建属性文件。
- 通过kset_register实现了class、class->p->subsys与sysfs之间的关联(包括kobject、kobj_type、sysfs_dirent)
- 通过kobj_type、class_ktype、class_ktype->class_release、class_sysfs_ops等,实现了class相关属性文件的读写、class以及class对应kobject相关的释放接口等。
至此即完成class类型的注册。
针对class类型注册,主要涉及的接口包括__class_register、kset_register、add_class_attrs,这些接口的功能就是实现下图中的几个模块间结构体变量的关联。此处就不介绍这些接口的实现了,只要看懂了下图,这几个接口的实现自然即可理解。关于kobject和sysfs之间的关联,请参考之前的文档

class类型的注销
class类型的注销即是将上述图中的关联解除。涉及的接口为class_unregister、remove_class_attrs、kset_unregister。此处也不再展开。
已注册的设备与具体class类的关联
在之前介绍设备模块时,在设备的添加接口device_add中,通过调用device_add_class_symlinks接口,会实现devices与class的相互链接。此处再详细说明下这种关联的流程。
它们之间的关联是通过sysfs的sysfs_create_link接口实现的,其实是通过sysfs中的sysfs_dirent类型的变量实现的关联。在调用device_add_class_symlinks接口后,也就实现了下图中sysfs_dirent变量之间的链接(如下图画出了class类链接device的链接)。

class-kobject对象生命周期管理
针对class类型的变量而言,因其使用kobject、kref进行引用计数,因此针对class类型变量而言,其释放也由kobject模块负责,当针对class类型的引用计数为0时,则会触发kobject模块的kobject_release接口进行kobject对象的删除(主要是删除在sysfs中创建的sysfs_dirent类型的变量(该变量表示在sysfs中的文件及目录))以及释放与kset的绑定等,同时会调用该kobject的kobj_type方法中的release接口,调用自定义的释放接口,从而在实现kobject的删除之后,也实现自定义的释放操作。而针对class而言,具体class类型变量的释放与kobject_release之间的接口关系如下图所示。
在调用class_release进行class类型相关的释放时,其会释放xxx_class.p对应的内存(该内存空间在进行class注册(调用class_register时所创建)),同时调用该xxx_class.release继续进行定制化的释放操作。

以上即完成了class模块的分析,针对class模块也好、bus模块也好,只要我们把结构体之间的关联图画出来之后,基本上也就知道具体的实现了。针对内核文件,数据结构体很重要,理解了数据结构体之间的关联,也就大概知道了模块的具体实现。