现在的位置: 首页 > 综合 > 正文

Linux驱动模型——kobject剖析

2017年12月07日 ⁄ 综合 ⁄ 共 3915字 ⁄ 字号 评论关闭
/*struct kobj_type的声明*/
struct kobj_type
{
	/*用于释放kobject*/
	void (*release)(struct kobject *kobj);
	/*sys的操作表*/
	const struct sysfs_ops *sys_ops;
	/*内核对象的属性,对应于sys文件系统的文件*/
	struct attribute **default_attrs;
};


struct kobj_attribute
{
	struct attribute attr;
	ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
	ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);
};


struct attribute
{
	const char *name;
	struct module *owner;
	mode_t mode;
}




/**
 *  kobject初始化
 **/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
	char *err_str;
	/*参数检查*/
	if (!kobj) {
		err_str = "invalid kobject pointer!";
		goto error;
	}
	if (!ktype) {
		err_str = "must have a ktype to be initialized properly!\n";
		goto error;
	}
	/*不能重复初始化*/
	if (kobj->state_initialized) {
		/* do not error out as sometimes we can recover */
		printk(KERN_ERR "kobject (%p): tried to init an initialized "
		       "object, something is seriously wrong.\n", kobj);
		dump_stack();
	}
	/*初始化*/
	kobject_init_internal(kobj);
	/*设置类型*/
	kobj->ktype = ktype;
	return;


error:
	printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
	dump_stack();
}


static void kobject_init_internal(struct kobject *kobj)
{
	/*参数检查*/
	if (!kobj)
		return;
	/*初始化引用计数*/
	kref_init(&kobj->kref);
	/*初始化链入链表的节点*/
	INIT_LIST_HEAD(&kobj->entry);
	/*初始化kobject的状态*/
	kobj->state_in_sysfs = 0;
	kobj->state_add_uevent_sent = 0;
	kobj->state_remove_uevent_sent = 0;
	kobj->state_initialized = 1;
}


/*添加到sys文件系统*/
int kobject_add(struct kobject *kobj, struct kobject *parent,
		const char *fmt, ...)
{
	va_list args;
	int retval;
	/*参数检查*/
	if (!kobj)
		return -EINVAL;
	/*必须已经初始化过*/
	if (!kobj->state_initialized) {
		printk(KERN_ERR "kobject '%s' (%p): tried to add an "
		       "uninitialized object, something is seriously wrong.\n",
		       kobject_name(kobj), kobj);
		dump_stack();
		return -EINVAL;
	}
	/*详见不定参数的编写*/
	va_start(args, fmt);
	/*这是本函数的一个包装*/
	retval = kobject_add_varg(kobj, parent, fmt, args);
	va_end(args);


	return retval;
}


static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
			    const char *fmt, va_list vargs)
{
	int retval;
	/*设置kobject的名字*/
	retval = kobject_set_name_vargs(kobj, fmt, vargs);
	if (retval) {
		printk(KERN_ERR "kobject: can not set name properly!\n");
		return retval;
	}
	/*设置父kobj*/
	kobj->parent = parent;
	/*来,开始添加*/
	return kobject_add_internal(kobj);
}


/**
 * kobject_set_name_vargs - Set the name of an kobject
 * @kobj: struct kobject to set the name of
 * @fmt: format string used to build the name
 * @vargs: vargs to format the string.
 */
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
				  va_list vargs)
{
	const char *old_name = kobj->name;
	char *s;
	/*参数检查*/
	if (kobj->name && !fmt)
		return 0;
	/*char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap),合成字符串*/
	kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
	/*创建失败*/
	if (!kobj->name)
		return -ENOMEM;


	/* ewww... some of these buggers have '/' in the name ... */
	/*替换路径中的'/'为'!',你懂的*/
	while ((s = strchr(kobj->name, '/')))
		s[0] = '!';
	/*释放老的名字*/
	kfree(old_name);
	return 0;
}


static int kobject_add_internal(struct kobject *kobj)
{
	int error = 0;
	struct kobject *parent;
	/*参数检查*/
	if (!kobj)
		return -ENOENT;


	if (!kobj->name || !kobj->name[0]) {
		WARN(1, "kobject: (%p): attempted to be registered with empty "
			 "name!\n", kobj);
		return -EINVAL;
	}
	/*增加父kobject的引用计数*/
	parent = kobject_get(kobj->parent);


	/* join kset if set, use it as parent if we do not already have one */
	if (kobj->kset) {
		if (!parent)
			parent = kobject_get(&kobj->kset->kobj);
		//添加到kset
		kobj_kset_join(kobj);
		kobj->parent = parent;
	}


	pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
		 kobject_name(kobj), kobj, __func__,
		 parent ? kobject_name(parent) : "<NULL>",
		 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
	//创建目录和文件
	error = create_dir(kobj);
	//创建失败,进行回滚
	if (error) {
		kobj_kset_leave(kobj);
		kobject_put(parent);
		kobj->parent = NULL;


		/* be noisy on error issues */
		if (error == -EEXIST)
			printk(KERN_ERR "%s failed for %s with "
			       "-EEXIST, don't try to register things with "
			       "the same name in the same directory.\n",
			       __func__, kobject_name(kobj));
		else
			printk(KERN_ERR "%s failed for %s (%d)\n",
			       __func__, kobject_name(kobj), error);
		dump_stack();
	} else
		//创建成功
		kobj->state_in_sysfs = 1;


	return error;
}


static int create_dir(struct kobject *kobj)
{
	int error = 0;
	if (kobject_name(kobj)) {
		//创建kobject对应的目录
		error = sysfs_create_dir(kobj);
		if (!error) {
			//创建kobj对应属性的文件
			error = populate_dir(kobj);
			if (error)
				//创建失败,进行回滚
				sysfs_remove_dir(kobj);
		}
	}
	return error;
}

抱歉!评论已关闭.