类是一个设备的高层视图,它抽象出了底层的实现细节,从而允许用户空间使用设备所提供的功能,而不用关心设备是如何连接和工作的。类成员通常由上层代码所控制,而无需驱动的明确支持。但有些情况下驱动也需要直接处理类。
在驱动开发中,多使用mknod命令手动创建设备节点,但当动态申请设备号时必须通过命令查出设备号,再添加。或者使用DEVFS文件系统函数添加设备节点。DEVFS在现在linux内核中已取消,取而代之的是UDEV,UDEV是处于用户态的程序。它根据内核发出的EVENTS,动态创建事件。内核是通过device_create发出event.而在device_create中就有一个参数是class,这个参数最终会在device_create中->device_create_vargs->device_register->device_add中调用device_create_sys_dev_entry在/sys/dev目录建立对设备的软链接。、
首先还是来看下calss相关的数据结构:
struct class { const char *name; //设备的名称,出现在/sys/class目录下 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); //class释放时调用 void (*dev_release)(struct device *dev); //设备释放时调用 int (*suspend)(struct device *dev, pm_message_t state);/* 设备暂停 */ int (*resume)(struct device *dev); /* 设备启动 */ const struct kobj_ns_type_operations *ns_type; const void *(*namespace)(struct device *dev); const struct dev_pm_ops *pm;//电源管理用的函数集 struct class_private *p; };struct class就是设备驱动模型中通用的设备类结构,和bus,device一样,它也有一个private结构:
struct class_private { struct kset class_subsys;//kset类型,代表class在sysfs中的位置 struct klist class_devices; //klist类型,是class下的设备链表 struct list_head class_interfaces;//list_head类型的类接口链表 struct kset class_dirs; struct mutex class_mutex;//互斥信号量, struct class *class; //回指所属的struct class结构 };class_interfaces是类接口链表
//描述设备类对外的一种接口 struct class_interface { struct list_head node;//class->p->class_interface链表上的节点 struct class *class;//指向所属class的指针 int (*add_dev) (struct device *, struct class_interface *);//有设备添加到所属class时调用的函数 void (*remove_dev) (struct device *, struct class_interface *);//remove_dev()是在设备删除时调用 };
static const struct sysfs_ops class_sysfs_ops = { .show = class_attr_show, .store = class_attr_store, }; static struct kobj_type class_ktype = { .sysfs_ops = &class_sysfs_ops, .release = class_release, .child_ns_type = class_child_ns_type, };关于ktype和bus,device一样,提供了一些默认的属性和操作函数。
再来看一下相关的操作函数:
int __init classes_init(void) { class_kset = kset_create_and_add("class", NULL, NULL);//在sysfs顶层创建class目录 if (!class_kset) return -ENOMEM; return 0; }init也跟bus等一样,创建kset,注册到sysfs.
再来看下提供给外面调用的创建class函数
#define class_create(owner, name) \ ({ \ static struct lock_class_key __key; \ __class_create(owner, name, &__key); \ })继续跟踪__class_create
struct class *__class_create(struct module *owner, const char *name, struct lock_class_key *key) { struct class *cls; int retval; cls = kzalloc(sizeof(*cls), GFP_KERNEL);//分配class结构 if (!cls) { retval = -ENOMEM; goto error; } cls->name = name;//设置name cls->owner = owner;//设置owner cls->class_release = class_create_release;//设置类释放函数 retval = __class_register(cls, key);//注册calss if (retval) goto error; return cls; error: kfree(cls); return ERR_PTR(retval); }这里主要是调用__class_register
int __class_register(struct class *cls, struct lock_class_key *key) { struct class_private *cp; int error; pr_debug("device class '%s': registering\n", cls->name); cp = kzalloc(sizeof(*cp), GFP_KERNEL);//分配class_private结构 if (!cp) return -ENOMEM; klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);//初始化class_private结构 INIT_LIST_HEAD(&cp->class_interfaces); kset_init(&cp->class_dirs);//初始化kset,并未加到sysfs __mutex_init(&cp->class_mutex, "struct class mutex", key); error = kobject_set_name(&cp->class_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 cls->dev_kobj = sysfs_dev_char_kobj; #if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK) /* let the block class directory show up in the root of sysfs */ if (cls != &block_class) cp->class_subsys.kobj.kset = class_kset; #else cp->class_subsys.kobj.kset = class_kset; #endif cp->class_subsys.kobj.ktype = &class_ktype; cp->class = cls; cls->p = cp; error = kset_register(&cp->class_subsys);//将class注册到sysfs中 if (error) { kfree(cp); return error; } error = add_class_attrs(class_get(cls));//添加相关的属性文件 class_put(cls); return error; }这个函数主要是对private结构操作,不像bus,device它的kobject结构在private里面,所以主要的操作基本都是对private
int class_interface_register(struct class_interface *class_intf) { struct class *parent; struct class_dev_iter iter; struct device *dev; if (!class_intf || !class_intf->class) return -ENODEV; parent = class_get(class_intf->class);//增加class的引用计数 if (!parent) return -EINVAL; mutex_lock(&parent->p->class_mutex); list_add_tail(&class_intf->node, &parent->p->class_interfaces); if (class_intf->add_dev) { class_dev_iter_init(&iter, parent, NULL, NULL); while ((dev = class_dev_iter_next(&iter))) class_intf->add_dev(dev, class_intf);//添加到class的接口列表中 class_dev_iter_exit(&iter); } mutex_unlock(&parent->p->class_mutex); return 0; }class的流程图也比较简单