class注册流程

本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记

一. class结构体描述
struct class{
	const char		*name;                            //class的名称,会在“/sys/class/”目录下体现
	struct module		*owner;
	struct class_attribute		*class_attrs;         //该class的默认attribute
	struct device_attribute		*dev_attrs;           //该class下每个设备的attribute
	struct kobject			*dev_kobj; //表示该class下的设备在/sys/dev/下的目录,现在一般有char和block两个,如果dev_kobj为NULL,则默认选择char
	int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); //当该class下有设备发生变化时,会调用class的uevent回调函数
	char *(*devnode)(struct device *dev, mode_t *mode);
	void (*class_release)(struct class *class);       //用于release自身的回调函数
	void (*dev_release)(struct device *dev);          //用于release class内设备的回调函数
	int (*suspend)(struct device *dev, pm_message_t state);
	int (*resume)(struct device *dev);
	const struct dev_pm_ops *pm;
	struct class_private *p;                           //class的私有数据
}
二. class模块初始化

创建一个class_kset,parent = NULL, kset->kobj.kset = NULL,相当于新建文件夹/sys/class

int __init classes_init(void)
{
	class_kset = kset_create_and_add("class", NULL, NULL);
	if (!class_kset)
		return -ENOMEM;
	return 0;
}

class_kset .uevent_ops = NULL;

三. class的创建函数class_create
dca_class = class_create(THIS_MODULE, "dca");
    __class_create(owner, name, &__key);
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);
	if (!cls) {
		retval = -ENOMEM;
		goto error;
	}

	cls->name = name;
	cls->owner = owner;
	cls->class_release = class_create_release;

	retval = __class_register(cls, key);
	if (retval)
		goto error;

	return cls;

error:
	kfree(cls);
	return ERR_PTR(retval);
}

调用class_create接口创建一个class,class_create调用的是__class_create。
__class_create接口里面分配了一个struct class类型的内存,然后调用__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);
	if (!cp)
		return -ENOMEM;
	klist_init(&cp->class_devices, klist_class_dev_get, klist_class_dev_put);
	INIT_LIST_HEAD(&cp->class_interfaces);
	kset_init(&cp->class_dirs);
	__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;

#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);
	if (error) {
		kfree(cp);
		return error;
	}
	error = add_class_attrs(class_get(cls));
	class_put(cls);
	return error;
}

1.申请class的私有数据cp

cp = kzalloc(sizeof(*cp), GFP_KERNEL);

2.cp->class_subsys的初始化

kobject_set_name(&cp->class_subsys.kobj, "%s", cls->name);
cp->class_subsys.kobj.kset = class_kset;
cp->class_subsys.kobj.ktype = &class_ktype;

class_subsys.kobj.kset = class_kset,相当于在/sys/class目录下创建一个名称为 cls->name的文件夹。

static struct kobj_type class_ktype = {
	.sysfs_ops	= &class_sysfs_ops,
	.release	= class_release,
};

展开得到:

static struct kobj_type class_ktype = {
	.sysfs_ops	=
	{
		.show	= class_attr_show,
		.store	= class_attr_store,
	}
	.release	= class_release,
};

3.上面的注册没有给cls->dev_kobj赋值,因此cls->dev_kobj = sysfs_dev_char_kobj。
sysfs_dev_char_kobj在devices_init函数中注册,这个kobj的目录是/sys/dev/char。

if (!cls->dev_kobj)
    cls->dev_kobj = sysfs_dev_char_kobj;

4.注册class kset,相当于在/sys/class目录下新建一个文件夹

error = kset_register(&cp->class_subsys);

5.创建class的属性文件

error = add_class_attrs(class_get(cls));
static int add_class_attrs(struct class *cls)
{
	int i;
	int error = 0;

	if (cls->class_attrs) {
		for (i = 0; attr_name(cls->class_attrs[i]); i++) {
			error = class_create_file(cls, &cls->class_attrs[i]);
			if (error)
				goto error;
		}
	}
done:
	return error;
error:
	while (--i >= 0)
		class_remove_file(cls, &cls->class_attrs[i]);
	goto done;
}
int class_create_file(struct class *cls, const struct class_attribute *attr)
{
	int error;
	if (cls)
		error = sysfs_create_file(&cls->p->class_subsys.kobj,
					  &attr->attr);
	else
		error = -EINVAL;
	return error;
}

由上面可以得到:

error = add_class_attrs(class_get(cls));
	error = class_create_file(cls, &cls->class_attrs[i]);
		error = sysfs_create_file(&cls->p->class_subsys.kobj, &attr->attr);

add_class_attrs函数在class目录创建了class的默认attribute文件。
找一个gpio_class的例子,如下所示:

static struct class gpio_class = {
	.name =		"gpio",
	.owner =	THIS_MODULE,
	.class_attrs =	gpio_class_attrs,
};
static struct class_attribute gpio_class_attrs[] = {
	__ATTR(export, 0200, NULL, export_store),
	__ATTR(unexport, 0200, NULL, unexport_store),
	__ATTR_NULL,
};

展开gpio_class ,得到:

static struct class gpio_class = {
	.name =		"gpio",
	.owner =	THIS_MODULE,
	.class_attrs =
	{
		.attr = {.name = “export”, .mode = 0200},
		.show = NULL,
		.store = export_store,
	},
	{
		.attr = {.name = “unexport”, .mode = 0200},
		.show = NULL,
		.store = unexport_store,	
	},
};

结果是在gpio这个class目录下创建了export文件,这个文件的写函数为export_store;
在gpio这个class目录下创建了unexport文件,这个文件的写函数是unexport_store;

上面的class_ktype 展开得到:

static struct kobj_type class_ktype = {
	.sysfs_ops	=
	{
		.show	= class_attr_show,
		.store	= class_attr_store,
	}
	.release	= class_release,
};

static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
	struct class_attribute *class_attr = to_class_attr(attr);
	struct class_private *cp = to_class(kobj);
	ssize_t ret = -EIO;

	if (class_attr->show)
		ret = class_attr->show(cp->class, buf);
	return ret;
}

static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)
{
	struct class_attribute *class_attr = to_class_attr(attr);
	struct class_private *cp = to_class(kobj);
	ssize_t ret = -EIO;

	if (class_attr->store)
		ret = class_attr->store(cp->class, buf, count);
	return ret;
}

那么相当于写gpio_class目录下的export和unexport文件,最终调用的函数是export_store和unexport_store。

四. class的注册函数class_register
#define class_register(class)			\
({						\
	static struct lock_class_key __key;	\
	__class_register(class, &__key);	\
})

class_register注册一个已经定义好了的class,直接调用__class_register函数,不用申请class内存。
__class_register函数在上面已经分析过了。

五. class_create和class_register

class_create是创建一个原先不存在的class,class_register是注册一个已经定义的class到内核。
class_create注册的class需要内核主动释放申请的class内存,而class_register注册的class一般在driver里面定义成了全局变量,不用去主动释放内存。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值