linux configfs(以usb_gadget为例)
configfs介绍linux 中configfs的官方介绍文档为documentation/filesystems/configfs.rst,关键信息如下:configfs - Userspace-driven kernel object configuration.直接翻译过来就是用户空间配置内核对象,在configfs.rst中可以看到其中的描述:configfs是一个基于ram的文件系统,
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);
更多推荐
所有评论(0)