class_register源码研究 思考一个问题,既然有了bus能满足所有设备的驱动匹配和探测,为什么还要引入class呢比如你插了一个 USB 键盘、一个蓝牙键盘和一个笔记本自带的 PS/2 键盘从bus视角看,他们分别属于不同的总线,驱动也完全不同,在/dev下创建inode的话也很难归类到一起但是从class视角看,他们都是输入设备,可以被归入input_class,让别的子系统模块监听input_class,从而为其统一分配身份和/dev下的inode节点所以总的来说,bus负责物理结构,class负责逻辑结构class结构体name:class的名字,对应注册到sysfs中kobj的名字owner:表示该类的主人模块,即只要该类还在使用,对应的模块就不能被卸载,一般定义的时候写为THIS_MODULEclass_attrs:类本身的默认属性,会在class的对应文件夹下面创建dev_groups:该类设备的默认属性,会在class/设备名/下创建对应的文件dev_kobj:指向在sysfs体系结构中代表该类的kobj,也代表了该class在/sys/class下的目录,其实也就是subsys_private的kset的内嵌kobjdev_uevent:class下有设备增加或者删除的时候发送uevent给用户空间的回调函数devnode:这个函数是在device_add()后被调用,负责分配该设备在/dev下的路径和权限,传递给devtmpfs去/dev下真正创建inode设备节点class_release:class释放的时候调用,这个是给内核回调用的dev_release:当class下的device被释放后被调用,做善后工作suspend:让类设备进入睡眠模式resume:从睡眠模式恢复类设备shutdown:关机的时候对class下的每个设备调用,安全关闭设备ns_type:这是命名空间的类型,如果为空,就表示该类没有设置命名空间,通过回调它可以确定class的命名空间namespace:该类的命名空间pm:指向电源管理器p:指向class的私有数据结构,理解为子系统,该子系统才是真正在sysfs中的目录这里和bus那边的subsys_private很类似subsys_private结构体该结构体是被bus_type和class共用的,所以其中一些成员class并没有使用subsys:代表当前class在sysfs体系结构中的kset,也代表了当前class在/sys/class/下的目录devices_kset:代表了子系统中devices的目录,在class中,就是class自己目录本身,bus中则是devices目录interfaces:让第三方内核模块能够订阅某个class下的设备添加或者移除的接口,其插入到interfaces链表的结构体如下.其实也很好理解,就是当设备被注册到class上的时候,调用所有的class_interface中的add_dev()函数做第三方模块的对应操作总而言之,就是让别的模块可以添加自己的接口来监听该class类上的设备,当该class有设备被添加或者移除的时候,能够自动调用上面这两个函数,做出一些对应的操作比如evdev模块就添加自己的接口来监听input_class上设备的注册,然后class调用interfaces链表中的所有class interface的add_dev()函数,该函数自己再去/dev/input/下创建对应的eventx的inode设备节点mutex:操作class的互斥锁drivers_kset:class不用这个属性klist_devices:用于线程安全的遍历class下devices们的链表,其配合klist_node实现多线程访问,删除的安全性(参照bus_register源码研究末尾的描述)klist_drivers:class不用这个属性bus_notifier:class不用这个属性drivers_autoprobe:class不用这个属性bus:class不用这个属性glue_dirs:class下所属的胶水目录的集合,这个胶水目录能保证找到所属类的设备,还能维持设备的父子关系,详见[device_add源码研究]class:指回自己所属class的指针class_register再套一层是为了让编译器能兼容不同的对__key的实现具体内容都在__class_register__class_register首先依旧是先为subsys_private变量申请空间176行对klist_devices链表进行初始化,然后定义线程安全访问该klist的特殊引用计数方法177行对interfaces链表进行初始化,这个里面为关注class添加或者删除的模块提供了回调方法的创建地方,同时,class自己属于自己的设备到/sys/devices下真实设备节点链接的功能 也是在这个链表内其中一个interface中实现的178行对glue_dirs进行初始化,胶水目录解释详见 [device_add源码研究]180行对class私有结构体中subsys这个kset内嵌的kobj设置名字,对应着/sys/class/类名187行为对该类中的设备在/sys/dev目录下如何显示进行默认处理,即在添加设备到类的时候会在/sys/dev/char/目录或者block下面创建对/sys/devices的链接文件因为/sys/dev下默认管理的都是块设备和一些字符设备190行,决定是否将块类设备直接显示在/sys/的根目录下,而不是放在/sys/class/下197行,对代表class的内嵌kobj设置ktype为class_ktype,即内核对他的管理按照类的方式来,当release的时候就会使用container_of获取到类结构体,再释放198行,对subsys_private和class进行双向连接201行,注册subsys_private中的名为subsys的kset,这里才会真正在/sys/中创建当前class对应的目录206行,为当前class在sysfs对应的目录下,创建属性文件—感觉这个很少用诶207行,class的引用计数-1class释放手动调用class_unregister的时候,实际上删除的仅仅是subsys_private中的subsys这个kset对应的目录,并且修改其状态为不在sysfs体系结构中,然后将引用计数-1经过上面的代码后,class-subsys_private-subsys-kobj的引用计数,就-1了,并且在sysfs中的状态标志为也为0了,这时别人只能让引用计数继续-1,没法再获取引用了,直到引用计数为0的话内核会自动按照ktype使用container_of获得对应的class结构体的大小,然后释放这块内存