系列文章目录
Linux 设备树
Linux 下注册分析(1)
Linux 下注册分析(2)
Linux 下注册分析(3)
Linux 下注册分析(4)
文章目录
- 系列文章目录
- 1、device_create
- 简介
- device_create
- device_create_groups_vargs
- 2、class_register
- 简介
- struct class
- class_register
- 3、class_create
- 4、class_interface_register
1、device_create
简介
device_create
用于创建设备并在 sysfs 中注册指向该设备应该注册到的结构类的指针。这个函数可以被 char 设备类使用。
device_create
// drivers/base/core.c
struct device *device_create(const struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
{va_list vargs;struct device *dev;va_start(vargs, fmt);dev = device_create_groups_vargs(class, parent, devt, drvdata, NULL,fmt, vargs);va_end(vargs);return dev;
}
EXPORT_SYMBOL_GPL(device_create);
device_create_groups_vargs
// drivers/base/core.c
static __printf(6, 0) struct device *
device_create_groups_vargs(const struct class *class, struct device *parent,dev_t devt, void *drvdata,const struct attribute_group **groups,const char *fmt, va_list args)
{struct device *dev = NULL;int retval = -ENODEV;if (IS_ERR_OR_NULL(class))goto error;dev = kzalloc(sizeof(*dev), GFP_KERNEL); // 为设备分配空间if (!dev) {retval = -ENOMEM;goto error;}device_initialize(dev); // 初始化设备结构体dev->devt = devt;dev->class = class;dev->parent = parent;dev->groups = groups;dev->release = device_create_release;dev_set_drvdata(dev, drvdata);retval = kobject_set_name_vargs(&dev->kobj, fmt, args);if (retval)goto error;retval = device_add(dev); // 把设备加入到总线上if (retval)goto error;return dev;error:put_device(dev);return ERR_PTR(retval);
}
device_register
函数
// drivers/base/core.c
int device_register(struct device *dev)
{device_initialize(dev);return device_add(dev);
}
从上可以看出,device_create()
调用了 device_initialize
和 device_add
两个函数,而这恰恰是 device_register()
做的工作,因此其等效于 device_register()
。
device_register 函数分析见 Linux 下注册分析(4)# device_register
device_add 函数分析见 Linux 下注册分析(4)# device_add
device_create()、device_register()、deivce_add()区别
2、class_register
简介
在 Linux 系统中,class_register
是一个非常重要的概念。它是 Linux 内核中用来管理设备驱动程序的一种机制,通过对设备进行分类注册,实现设备间的协作和管理。在 Linux 系统中,设备驱动程序是连接硬件设备和操作系统内核的桥梁,而 class_register 机制可以帮助内核更好地管理这些设备驱动程序,并且提供一种灵活的方式来处理设备的注册和注销。
struct class
// include/linux/device/class.h
struct class {const char *name;const struct attribute_group **class_groups;const struct attribute_group **dev_groups;int (*dev_uevent)(const struct device *dev, struct kobj_uevent_env *env);char *(*devnode)(const struct device *dev, umode_t *mode);void (*class_release)(const struct class *class);void (*dev_release)(struct device *dev);int (*shutdown_pre)(struct device *dev);const struct kobj_ns_type_operations *ns_type;const void *(*namespace)(const struct device *dev);void (*get_ownership)(const struct device *dev, kuid_t *uid, kgid_t *gid);const struct dev_pm_ops *pm;
};
class_register
// drivers/base/class.c
int class_register(const struct class *cls)
{struct subsys_private *cp;struct lock_class_key *key;int error;pr_debug("device class '%s': registering\n", cls->name);if (cls->ns_type && !cls->namespace) {pr_err("%s: class '%s' does not have namespace\n",__func__, cls->name);return -EINVAL;}if (!cls->ns_type && cls->namespace) {pr_err("%s: class '%s' does not have ns_type\n",__func__, cls->name);return -EINVAL;}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);key = &cp->lock_key;lockdep_register_key(key);__mutex_init(&cp->mutex, "subsys mutex", key);error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);if (error)goto err_out;cp->subsys.kobj.kset = class_kset;cp->subsys.kobj.ktype = &class_ktype;cp->class = cls;error = kset_register(&cp->subsys);if (error)goto err_out;error = sysfs_create_groups(&cp->subsys.kobj, cls->class_groups);if (error) {kobject_del(&cp->subsys.kobj);kfree_const(cp->subsys.kobj.name);goto err_out;}return 0;err_out:lockdep_unregister_key(key);kfree(cp);return error;
}
kset_register
详细分析见 Linux 下注册分析(1)# kset_register
sysfs_create_groups
详细分析见 Linux 下注册分析(1)# sysfs_create_groups
3、class_create
struct class *class_create(const char *name)
{struct class *cls;int retval;cls = kzalloc(sizeof(*cls), GFP_KERNEL); // 分配 class 空间if (!cls) {retval = -ENOMEM;goto error;}cls->name = name;cls->class_release = class_create_release;retval = class_register(cls); // 注册 class,见上面 class_registerif (retval)goto error;return cls;error:kfree(cls);return ERR_PTR(retval);
}
由上可以看出 class_create
在分配 class 结构体后,然后再调用 class_register
函数。
4、class_interface_register
// drivers/base/class.c
int class_interface_register(struct class_interface *class_intf)
{struct subsys_private *sp;const struct class *parent;struct class_dev_iter iter;struct device *dev;if (!class_intf || !class_intf->class)return -ENODEV;parent = class_intf->class;sp = class_to_subsys(parent); // 获取 class 的 subsys_private if (!sp)return -EINVAL;/** Reference in sp is now incremented and will be dropped when* the interface is removed in the call to class_interface_unregister()*/mutex_lock(&sp->mutex);// 把 class_interface 链到 sp->interfaces 上list_add_tail(&class_intf->node, &sp->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_dev_iter_exit(&iter);}mutex_unlock(&sp->mutex);return 0;
}
【Linux内核|驱动模型】bus/class/device/driver
☆