configfs介绍

linux 中configfs的官方介绍文档为documentation/filesystems/configfs.rst,关键信息如下:
configfs - Userspace-driven kernel object configuration.直接翻译过来就是用户空间配置内核对象,在configfs.rst中可以看到其中的描述:
configfs是一个基于ram的文件系统,通过对该文件系统的操作实现对内核对象的配置。

configfs组成

根据configfs.rst的说明我们可以抽象的理解configfs的文件主要分成三层:
1、configfs_subsystem (子系统)
2、configfs_grounp(组层)
3、config_item.
我们在使用时候一般会创建一个config_subsystem,再在这个子系统下边创建config_group,在config_group创建config_item,然后具体的操作都是config_item相关的,config_item中的接口的具体实现就是文件的具体操作,最终的交互执行者都是以item为单位的,包括读写创建和删除。

configfs使用实例

下面以usb的配置为实例介绍configfs的使用。
首先在driver/usb/gadget/configfs.c里面注册usb gadget子系统:

static struct configfs_subsystem gadget_subsys = {
	.su_group = {
		.cg_item = {
			.ci_namebuf = "usb_gadget",
			.ci_type = &gadgets_type,
		},
	},
	.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
};

static int __init gadget_cfs_init(void)
{
	int ret;

	config_group_init(&gadget_subsys.su_group);
	ret = configfs_register_subsystem(&gadget_subsys);

#ifdef CONFIG_USB_CONFIGFS_UEVENT
	android_class = class_create(THIS_MODULE, "android_usb");
	if (IS_ERR(android_class))
		return PTR_ERR(android_class);
#endif

	return ret;
}
module_init(gadget_cfs_init);

这样mount configfs以后在/config下就会出现usb_gadget目录:
在这里插入图片描述
第二步就是像子系统中添加configfs_grounp

static struct configfs_group_operations gadgets_ops = {
	.make_group     = &gadgets_make,
	.drop_item      = &gadgets_drop,
};

static const struct config_item_type gadgets_type = {
	.ct_group_ops   = &gadgets_ops,
	.ct_owner       = THIS_MODULE,
};

gadget_subsys 中的指定了.ci_type = &gadgets_type,所以实际创建configfs_group的操作是gadgets_make:

static struct config_group *gadgets_make(struct config_group *group, const char *name){
.......
	config_group_init_type_name(&gi->group, name, &gadget_root_type);

	config_group_init_type_name(&gi->functions_group, "functions", &functions_type);
	configfs_add_default_group(&gi->functions_group, &gi->group);
	config_group_init_type_name(&gi->configs_group, "configs", &config_desc_type);
	configfs_add_default_group(&gi->configs_group, &gi->group);
	config_group_init_type_name(&gi->strings_group, "strings", &gadget_strings_strings_type);
	configfs_add_default_group(&gi->strings_group, &gi->group);
	config_group_init_type_name(&gi->os_desc_group, "os_desc", &os_desc_type);
	configfs_add_default_group(&gi->os_desc_group, &gi->group);
......
}

其中gadget_root_type下面又包含了其他item:
static struct configfs_attribute *gadget_root_attrs[] = {
&gadget_dev_desc_attr_bDeviceClass,
&gadget_dev_desc_attr_bDeviceSubClass,
&gadget_dev_desc_attr_bDeviceProtocol,
&gadget_dev_desc_attr_bMaxPacketSize0,
&gadget_dev_desc_attr_idVendor,
&gadget_dev_desc_attr_idProduct,
&gadget_dev_desc_attr_bcdDevice,
&gadget_dev_desc_attr_bcdUSB,
&gadget_dev_desc_attr_UDC,
NULL,
};
functions configs strings os_desc 又是一个group,即表征为一个子目录。这样usb_gaget下面的组件就已经成型了:
在这里插入图片描述
对于具体的每一个config_item 都会提供读写操作,这点和sysfs类似,比如UDC item的读写操作函数如下:


static ssize_t gadget_dev_desc_UDC_show(struct config_item *item, char *page)
{
	char *udc_name = to_gadget_info(item)->composite.gadget_driver.udc_name;

	return sprintf(page, "%s\n", udc_name ?: "");
}

static ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
		const char *page, size_t len)
{
	struct gadget_info *gi = to_gadget_info(item);
	char *name;
	int ret;

	if (strlen(page) < len)
		return -EOVERFLOW;

	name = kstrdup(page, GFP_KERNEL);
	if (!name)
		return -ENOMEM;
	if (name[len - 1] == '\n')
		name[len - 1] = '\0';

	mutex_lock(&gi->lock);

	if (!strlen(name) || strcmp(name, "none") == 0) {
		ret = unregister_gadget(gi);
		if (ret)
			goto err;
		kfree(name);
	} else {
		if (gi->composite.gadget_driver.udc_name) {
			ret = -EBUSY;
			goto err;
		}
		gi->composite.gadget_driver.udc_name = name;
		ret = usb_gadget_probe_driver(&gi->composite.gadget_driver);
		if (ret) {
			gi->composite.gadget_driver.udc_name = NULL;
			goto err;
		}
		schedule_work(&gi->work);
	}
	mutex_unlock(&gi->lock);
	return len;
err:
	kfree(name);
	mutex_unlock(&gi->lock);
	return ret;
}

CONFIGFS_ATTR(gadget_dev_desc_, bDeviceClass);
CONFIGFS_ATTR(gadget_dev_desc_, bDeviceSubClass);
CONFIGFS_ATTR(gadget_dev_desc_, bDeviceProtocol);
CONFIGFS_ATTR(gadget_dev_desc_, bMaxPacketSize0);
CONFIGFS_ATTR(gadget_dev_desc_, idVendor);
CONFIGFS_ATTR(gadget_dev_desc_, idProduct);
CONFIGFS_ATTR(gadget_dev_desc_, bcdDevice);
CONFIGFS_ATTR(gadget_dev_desc_, bcdUSB);
CONFIGFS_ATTR(gadget_dev_desc_, UDC);
Logo

更多推荐