searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

linux设备模型class介绍

2024-12-06 09:31:02
0
0

Linux 的设备模型引入类,是将其用来作为具有同类型功能设备的一个容器,struct class定义的数据结构是:

struct class {
	const char		*name; // 类的名称
	struct module		*owner; // 拥有该类的模块的指针

	struct class_attribute		*class_attrs; // 类的属性
	const struct attribute_group	**class_groups;
	const struct attribute_group	**dev_groups; // 设备的属性
	struct kobject			*dev_kobj; // 代表当前类中设备的内核对象

	int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
	char *(*devnode)(struct device *dev, umode_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 kobj_ns_type_operations *ns_type;
	const void *(*namespace)(struct device *dev);

	const struct dev_pm_ops *pm;
	// 类的私有数据区,用于处理类的子系统及其所包含的设备链表
	struct subsys_private *p;
};

宏 class_create 用来生成一个类对象,其用途主要是将同类型的设备添加其中。该宏的核心是对函数__class_create 的调用,调用路径如下

#define class_create(owner, name)
  __class_create(owner, name, &__key);
    __class_register(cls, key);

__class_register函数的实现如下:

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);
	// 为__class_create 函数中生成的新的类对象分配私有数据空间
	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);
	// 将类对象的 name 成员赋值给代表类的 kobject 对象名称
	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;
	// 为类的 kobj 指定 kset 和 ktype
	// class_kset 为系统中所有 class 对象的顶层 kset, 此处将当前 class 对象的 kobj.kset
	// 指向 class_kset,意味着通过 class_create 生成的 class,在 sysfs 文件系统中的入口点(目录)
	// 将在/sys/class 目录下产生
#if defined(CONFIG_BLOCK)
	/* let the block class directory show up in the root of sysfs */
	if (!sysfs_deprecated || cls != &block_class)
		cp->subsys.kobj.kset = class_kset;
#else
	cp->subsys.kobj.kset = class_kset; // kset
#endif
	cp->subsys.kobj.ktype = &class_ktype; // ktype
	cp->class = cls;
	cls->p = cp;
	// 调用 kset_register 将之前产生的 class 加入到系统中
	// 这样将会在/sys/class 目录下生成一个新的目录
	error = kset_register(&cp->subsys);
	if (error) {
		kfree(cp);
		return error;
	}
	error = class_add_groups(class_get(cls), cls->class_groups);
	class_put(cls);
	error = add_class_attrs(class_get(cls));
	class_put(cls);
	return error;
}

在使用device_create创建设备对象时,传入的第一个参数即是class类变量,传入的class和parent变量决定被创建设备在/sys目录下的位置:

struct device *device_create(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_vargs(class, parent, devt, drvdata, fmt, vargs);
	va_end(vargs);
	return dev;
}

device_create_vargs
  device_create_groups_vargs

static struct device *
device_create_groups_vargs(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 (class == NULL || IS_ERR(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); // 设置 kobj->name
	if (retval)
		goto error;

	retval = device_add(dev); // 设备注册到系统
	if (retval)
		goto error;

	return dev;

error:
	put_device(dev);
	return ERR_PTR(retval);
}
0条评论
作者已关闭评论
c****q
8文章数
0粉丝数
c****q
8 文章 | 0 粉丝
原创

linux设备模型class介绍

2024-12-06 09:31:02
0
0

Linux 的设备模型引入类,是将其用来作为具有同类型功能设备的一个容器,struct class定义的数据结构是:

struct class {
	const char		*name; // 类的名称
	struct module		*owner; // 拥有该类的模块的指针

	struct class_attribute		*class_attrs; // 类的属性
	const struct attribute_group	**class_groups;
	const struct attribute_group	**dev_groups; // 设备的属性
	struct kobject			*dev_kobj; // 代表当前类中设备的内核对象

	int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
	char *(*devnode)(struct device *dev, umode_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 kobj_ns_type_operations *ns_type;
	const void *(*namespace)(struct device *dev);

	const struct dev_pm_ops *pm;
	// 类的私有数据区,用于处理类的子系统及其所包含的设备链表
	struct subsys_private *p;
};

宏 class_create 用来生成一个类对象,其用途主要是将同类型的设备添加其中。该宏的核心是对函数__class_create 的调用,调用路径如下

#define class_create(owner, name)
  __class_create(owner, name, &__key);
    __class_register(cls, key);

__class_register函数的实现如下:

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);
	// 为__class_create 函数中生成的新的类对象分配私有数据空间
	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);
	// 将类对象的 name 成员赋值给代表类的 kobject 对象名称
	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;
	// 为类的 kobj 指定 kset 和 ktype
	// class_kset 为系统中所有 class 对象的顶层 kset, 此处将当前 class 对象的 kobj.kset
	// 指向 class_kset,意味着通过 class_create 生成的 class,在 sysfs 文件系统中的入口点(目录)
	// 将在/sys/class 目录下产生
#if defined(CONFIG_BLOCK)
	/* let the block class directory show up in the root of sysfs */
	if (!sysfs_deprecated || cls != &block_class)
		cp->subsys.kobj.kset = class_kset;
#else
	cp->subsys.kobj.kset = class_kset; // kset
#endif
	cp->subsys.kobj.ktype = &class_ktype; // ktype
	cp->class = cls;
	cls->p = cp;
	// 调用 kset_register 将之前产生的 class 加入到系统中
	// 这样将会在/sys/class 目录下生成一个新的目录
	error = kset_register(&cp->subsys);
	if (error) {
		kfree(cp);
		return error;
	}
	error = class_add_groups(class_get(cls), cls->class_groups);
	class_put(cls);
	error = add_class_attrs(class_get(cls));
	class_put(cls);
	return error;
}

在使用device_create创建设备对象时,传入的第一个参数即是class类变量,传入的class和parent变量决定被创建设备在/sys目录下的位置:

struct device *device_create(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_vargs(class, parent, devt, drvdata, fmt, vargs);
	va_end(vargs);
	return dev;
}

device_create_vargs
  device_create_groups_vargs

static struct device *
device_create_groups_vargs(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 (class == NULL || IS_ERR(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); // 设置 kobj->name
	if (retval)
		goto error;

	retval = device_add(dev); // 设备注册到系统
	if (retval)
		goto error;

	return dev;

error:
	put_device(dev);
	return ERR_PTR(retval);
}
文章来自个人专栏
驱动
5 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0