class对应的代码在drivers/base/class.c中,对应的头文件在include/linux/device.h和drivers/base/base.h中。
/* * device classes */ struct class { const char *name; struct module *owner; struct class_attribute *class_attrs; struct device_attribute *dev_attrs; struct kobject *dev_kobj; int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); char *(*devnode)(struct device *dev, mode_t *mode); void (*class_release)(struct class *class); void (*dev_release)(struct device *dev); int (*suspend)(struct device *dev, pm_message_t state); int (*resume)(struct device *dev); const struct dev_pm_ops *pm; struct class_private *p; };
struct class就是设备驱动模型中通用的设备类结构。
name代表类名称,但和bus/device/driver中的名称一样,是初始名称,实际使用的是内部kobj包含的动态创建的名称。
owner是class所属的模块,虽然class是涉及一类设备,但也是由相应的模块注册的。比如usb类就是由usb模块注册的。
class_attrs是class给自己添加的属性,dev_attrs是class给所包含的设备添加的属性。这里就像bus中一样,只是bus是bus、driver、device全部包含的。
dev_kobj是一个kobject指针。在device注册时,会在/sys/dev下创建名为自己设备号的软链接。但设备不知道自己属于块设备还是字符设备,所以会请示自己所属的class,class就是用dev_kobj记录本类设备应属于的哪种设备。
dev_uevent()是在设备发出uevent消息时添加环境变量用的。还记得在core.c中的dev_uevent()函数,其中就包含对设备所属bus或class中dev_uevent()方法的调用,只是bus结构中定义方法用的函数名是uevent。
devnode()返回设备节点的相对路径名。在core.c的device_get_devnode()中有调用到。
class_release()是在class释放时调用到的。类似于device在结构中为自己定义的release函数。
dev_release()自然是在设备释放时调用到的。具体在core.c的device_release()函数中调用。
suspend()是在设备休眠时调用。
resume()是恢复设备时调用。
pm是电源管理用的函数集合,在bus、driver、class中都有看到,只是在device中换成了dev_pm_info结构,但device_type中还是隐藏着dev_pm_ops的指针。可见电源管理还是很重要的,只是这些东西都要结合具体的设备来分析,这里的设备驱动模型能给的,最多是一个函数指针与通用数据的框架。
p是指向class_private结构的指针:
struct class_private { struct kset class_subsys; struct klist class_devices; struct list_head class_interfaces; struct kset class_dirs; struct mutex class_mutex; struct class *class; };
struct class_private,是class连接到系统中的重要结构。
class_subsys是kset类型,代表class在sysfs中的位置。
class_devices是klist类型,是class下的设备链表。
class_interfaces是list_head类型的类接口链表,设备类接口稍后会介绍。
class_dirs也是kset类型,它并未实际在sysfs中体现,反而是其下链接了一系列胶水kobject。记得在core.c中的get_device_parent()函数,好像小蝌蚪找妈妈一样,我们在为新注册的设备寻找sysfs中可以存放的位置。如果发现dev->class存在,而dev->parent->class不存在,就要建立一个胶水目录,在sysfs中隔离这两个实际上有父子关系的设备。linux这么做也是为了在sysfs显示时更清晰一些。但如果父设备下有多个属于同一类的设备,它们需要放在同一胶水目录下。怎么寻找这个胶水目录有没有建立过,就要从这里的class_dirs下的kobject中找了。
class_mutex是互斥信号量,用于保护class内部的数据结构。
class是指回struct class的指针。
class接口函数:
class_register()将class注册到系统中。
class_unregister()取消class的注册。
class_create()是提供给外界快速创建class的API。
class_destroy()是与class_create()相对的删除class的函数。