Linux驱动SPI-7-class_register
本篇依旧致死量参考大佬内容class_register源码研究-CSDN博客class类static struct class spi_master_class { .name spi_master, .owner THIS_MODULE, .dev_release spi_master_release, .dev_groups spi_master_groups, };class类也是看起来很多实际用上的很少。owner:表示该类的主人模块,即只要该类还在使用,对应的模块就不能被卸载,一般定义的时候写为THIS_MODULEdev_groups:设备的属性组,会在class/设备名/下创建对应的文件releaseclass被释放相当于不用这种设备了其他改停止该取消的早就做好了。只需要kfree让出内存。static void spi_master_release(struct device *dev) { //一个指针 struct spi_master *master; dev_info(master-dev, spi_master_release enter! \n); /* 给定一个结构体成员member的指针ptr计算出该结构体type的起始地址 container_of(dev, struct spi_master, dev) 就得到了指向整个 spi_master 结构体的指针并赋值给 master 之后调用 kfree(master) 就可以释放这个 spi_master 结构体所占用的内存*/ master container_of(dev, struct spi_master, dev); kfree(master); }class_register注册类和注册总线一样也是配置注册一个subsys_private。#define class_register(class) \ ({ \ static struct lock_class_key __key; \ __class_register(class, __key); \ }) int __class_register(struct class *cls, struct lock_class_key *key) { struct subsys_private *cp; int error; pr_debug(device class %s: registering\n, cls-name); //分配空间 cp kzalloc(sizeof(*cp), GFP_KERNEL); if (!cp) return -ENOMEM; //初始化 klist_init(cp-klist_devices, klist_class_dev_get, klist_class_dev_put); INIT_LIST_HEAD(cp-interfaces); kset_init(cp-glue_dirs); __mutex_init(cp-mutex, subsys mutex, key); //设置名字 error kobject_set_name(cp-subsys.kobj, %s, cls-name); if (error) { kfree(cp); return error; } /* set the default /sys/dev directory for devices of this class */ //在下面 if (!cls-dev_kobj) cls-dev_kobj sysfs_dev_char_kobj; /* let the block class directory show up in the root of sysfs */ /*将当前类的 subsys.kobj即类自身的 kobject的 kset 指针指向全局的 class_kset 从而使得该类在 /sys/class/ 下出现。 class_kset 代表 /sys/class/ 目录是所有类注册时的默认父目录。 */ if (!sysfs_deprecated || cls ! block_class) cp-subsys.kobj.kset class_kset; cp-subsys.kobj.ktype class_ktype; cp-class cls;//和总线的区分就是有这个设置 cls-p cp; error kset_register(cp-subsys); if (error) { kfree(cp); return error; } //为类添加默认的 sysfs 属性文件 error add_class_attrs(class_get(cls)); class_put(cls); return error; }if (!cls-dev_kobj)cls-dev_kobj sysfs_dev_char_kobj;如果class注册时没有显式设置dev_kobj即为 NULL则默认使用sysfs_dev_char_kobj即/sys/dev/char/目录。确实没有特殊设置增加一个引用计数是因为add_class_attrs函数可能会访问cls中的成员例如属性列表并且可能因为某些原因如并发导致cls被释放。通过class_get先增加引用计数可以保证在调用add_class_attrs期间cls不会被其他代码释放。在spi目录下没看到class中也没有定义class_attrs这个东西不管这个。class_unregistervoid class_unregister(struct class *cls) { pr_debug(device class %s: unregistering\n, cls-name); remove_class_attrs(cls); kset_unregister(cls-p-subsys); } //这是对应add_class_attrs的spi不涉及 static void remove_class_attrs(struct class *cls) { int i; if (cls-class_attrs) { for (i 0; cls-class_attrs[i].attr.name; i) class_remove_file(cls, cls-class_attrs[i]); } } void kset_unregister(struct kset *k) { if (!k) return; kobject_del(k-kobj); kobject_put(k-kobj); } EXPORT_SYMBOL(kset_unregister);class-subsys_private-subsys-kobj引用计数-1kobj-state_in_sysfs 0不让其他设备引用这时别人只能让引用计数继续-1,没法再获取引用了,直到引用计数为0的话内核会自动按照ktype使用container_of获得对应的class,bus等结构体的大小,然后清除这块内存