简单分析configfs调用流程

参考资料:https://www.cnblogs.com/linhaostudy/p/17016238.html
https://blog.csdn.net/liujiliei/article/details/105276551
https://www.elecfans.com/d/1847582.html

1、configfs

configfs的文件主要分成三层:

  • configfs_subsystem (子系统)
  • configfs_grounp(组层)
  • config_item
struct gadget_info {
	struct config_group group;
	struct config_group functions_group;
	struct config_group configs_group;
	struct config_group strings_group;
	struct config_group os_desc_group;

	struct mutex lock;
	struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
	struct list_head string_list;
	struct list_head available_func;

	struct usb_composite_driver composite;
	struct usb_composite_dev cdev;
	bool use_os_desc;
	char b_vendor_code;
	char qw_sign[OS_STRING_QW_SIGN_LEN];
	spinlock_t spinlock;
	bool unbind;
};

struct config_group {
	struct config_item		cg_item;
	struct list_head		cg_children;
	struct configfs_subsystem 	*cg_subsys;
	struct list_head		default_groups;
	struct list_head		group_entry;
};

configfs.c和uvc_configfs.c联系起来

function_make  //configfs.c
	usb_get_function_instance(func_name)  //configfs.c
		try_get_usb_function_instance  //function.c
			usb_function_instance *uvc_alloc_inst(void)  //f_uvc,c
				ret = uvcg_attach_configfs(opts)  //f_uvc,c

//uvc_configfs.c
int uvcg_attach_configfs(struct f_uvc_opts *opts)
{
	int ret;
	config_group_init_type_name(&opts->func_inst.group, uvc_func_type.name,
				    &uvc_func_type.type);
	ret = uvcg_config_create_children(&opts->func_inst.group,
					  &uvc_func_type);
	if (ret < 0)
		config_group_put(&opts->func_inst.group);
	return ret;
}

ln 操作时会调用alloc_func:

config_group_init_type_name(&cfg->group, name,&gadget_config_type);
	config_usb_cfg_link
		usb_get_function(fi)
			fi->fd->alloc_func(fi)

2、Platform Layer

1、Platform Device

2、Platform Driver

//drivers/usb/dwc2/platform.c
static struct platform_driver dwc2_platform_driver = {
	.driver = {
		.name = dwc2_driver_name,
		.of_match_table = dwc2_of_match_table,
		.pm = &dwc2_dev_pm_ops,
	},
	.probe = dwc2_driver_probe,
	.remove = dwc2_driver_remove,
	.shutdown = dwc2_driver_shutdown,
};

module_platform_driver(dwc2_platform_driver);
//drivers/usb/dwc2/params.c:
const struct of_device_id dwc2_of_match_table[] = {
	{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
	{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params  },
	{ .compatible = "rockchip,rk3066-usb", .data = dwc2_set_rk_params },
	{ .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params },
	{ .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params },
	{ .compatible = "snps,dwc2" },
	{ .compatible = "samsung,s3c6400-hsotg",
	  .data = dwc2_set_s3c6400_params },
	{ .compatible = "amlogic,meson8-usb",
	  .data = dwc2_set_amlogic_params },
	{ .compatible = "amlogic,meson8b-usb",
	  .data = dwc2_set_amlogic_params },
	{ .compatible = "amlogic,meson-gxbb-usb",
	  .data = dwc2_set_amlogic_params },
	{ .compatible = "amlogic,meson-g12a-usb",
	  .data = dwc2_set_amlogic_g12a_params },
	{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
	{ .compatible = "st,stm32f4x9-fsotg",
	  .data = dwc2_set_stm32f4x9_fsotg_params },
	{ .compatible = "st,stm32f4x9-hsotg" },
	{ .compatible = "st,stm32f7-hsotg",
	  .data = dwc2_set_stm32f7_hsotg_params },
	{},
};
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);

该驱动的主要功能是创建和注册 Gadget Device,一个 UDC 对应一个 Gadget Device

//dwc2_driver_probe() → usb_add_gadget_udc() → usb_add_gadget_udc_release()
dwc2_driver_probe(struct platform_device *dev)   // drivers/usb/dwc2/platform.c
	usb_add_gadget_udc(hsotg->dev, &hsotg->gadget)   // gadget/udc/core.c
		usb_add_gadget_udc_release(parent, gadget, NULL)  // gadget/udc/core.c	

3、UDC/Gadget Layer

Gadget Layer 层把各式各样的 UDC 封装成标准的 Gadget Device,提供统一的向上接口。Gadget Driver 又把各式各样的 Function 和 Gadget Device 链接起来。

static struct platform_driver ambarella_udc_driver = {
	.driver		= {
		.name	= "ambarella-udc",
		.owner	= THIS_MODULE,
		.of_match_table	= ambarella_udc_dt_ids,
	},
	.remove		= ambarella_udc_remove,
#ifdef CONFIG_PM
	.suspend	= ambarella_udc_suspend,
	.resume		= ambarella_udc_resume,
#endif
};
module_platform_driver_probe(ambarella_udc_driver, ambarella_udc_probe);

ambarella_udc_probe(struct platform_device *pdev)
	 usb_add_gadget_udc_release
	 	check_pending_gadget_drivers(udc)
	 		udc_bind_to_driver(udc, driver)

1、Gadget Bus

Gadget Layer 层没有定义一个标准的 Bus 总线,而是自定义了两条链表来分别存储 Device 和 Driver
它们的使用场景如下:

  1. 在 Gadget Device 创建时,首先把 Device 加入到 udc_list 链表,然后尝试和 gadget_driver_pending_list 链表中的 Driver 进行 match()
//usb_add_gadget_udc() → usb_add_gadget_udc_release()→ check_pending_gadget_drivers
//→udc_bind_to_driver
usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
		void (*release)(struct device *dev))

/* should be called with udc_lock held */
static int check_pending_gadget_drivers(struct usb_udc *udc)
{
	struct usb_gadget_driver *driver;
	int ret = 0;

	list_for_each_entry(driver, &gadget_driver_pending_list, pending)
		if (!driver->udc_name || strcmp(driver->udc_name,
						dev_name(&udc->dev)) == 0) {
			ret = udc_bind_to_driver(udc, driver);
			if (ret != -EPROBE_DEFER)
				list_del_init(&driver->pending);
			break;
		}
	return ret;
}
  1. 在 Gadget Driver 创建时,首先尝试和 udc_list 链表中的 Device 进行 match(),match() 不成功则把 Driver 加入到 gadget_driver_pending_list 链表中
//gadget_dev_desc_UDC_store() → usb_gadget_probe_driver()
gadget_dev_desc_UDC_store   // gadget/configfs.c
	usb_gadget_probe_driver(&gi->composite.gadget_driver)	// gadget/udc/core.c
		udc_bind_to_driver(udc, driver)  // gadget/udc/core.c
			
  1. 在 Device 和 Driver Match 成功时的 bind() 动作
gadget_dev_desc_UDC_store   // gadget/configfs.c
	usb_gadget_probe_driver(&gi->composite.gadget_driver)	// gadget/udc/core.c
		udc_bind_to_driver(udc, driver)   // gadget/udc/core.c
			driver->bind(udc->gadget, driver)   // gadget/udc/core.c
				configfs_composite_bind	  // gadget/configfs.c
					usb_add_function(c, f)   // gadget/composite.c
						function->bind(config, function) // gadget/composite.c

static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
{
	int ret;

	dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
			driver->function);

	udc->driver = driver;
	udc->dev.driver = &driver->driver;
	udc->gadget->dev.driver = &driver->driver;

	usb_gadget_udc_set_speed(udc, driver->max_speed);

	ret = driver->bind(udc->gadget, driver);
	if (ret)
		goto err1;
	ret = usb_gadget_udc_start(udc);
	if (ret) {
		driver->unbind(udc->gadget);
		goto err1;
	}
	usb_udc_connect_control(udc);

	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
	return 0;
err1:
	if (ret != -EISNAM)
		dev_err(&udc->dev, "failed to start %s: %d\n",
			udc->driver->function, ret);
	udc->driver = NULL;
	udc->dev.driver = NULL;
	udc->gadget->dev.driver = NULL;
	return ret;
}

注意:这里和一般的 Device 和 Driver 的适配规则有些不一样。一般的规则是一个 Dirver 可以适配多个 Device,而一个 Device 只能适配一个 Driver。而这里的规则是一个 Gadget Device 只能适配一个 Gadget Driver,而一个 Gadget Driver 只能适配一个 Gadget Device。Gadget Device 代表的是一个 UDC,而 Gadget Driver 代表的是一个 Composite Device。

2、Gadget Device

Gadget Device 的主要作用是提供了 Endpoint 资源,供 Function Layer 使用标准的 Gadget API 来进行访问。

3、UDC Control

注册 Gadget Device 之前,初始化了 Gadget 的 操作函数集

ambarella_init_gadget
	udc->gadget.ops = &ambarella_ops
	
static const struct usb_gadget_ops ambarella_ops = {
	.get_frame		= ambarella_udc_get_frame,
	.wakeup			= ambarella_udc_wakeup,
	.pullup			= ambarella_udc_pullup,
	.vbus_session		= ambarella_udc_vbus_session,
	/*.set_selfpowered: Always selfpowered */
	.udc_start		= ambarella_udc_start,
	.udc_stop		= ambarella_udc_stop,
};

4、Gadget Driver (Configfs)

Gadget Device 支撑了核心 Gadget Api 的实现,而 Function Layer 又需要使用这些 Api。怎么样将两者适配起来?Gadget Driver 就是用来完成这项工作的。
目前存在两种风格的 Gadget Driver,其中包括:

  • Legacy。这是早期风格的 Gadget Driver,只能通过静态编译的方式指定使用哪些 Function。
  • Configfs。这是目前流行的 Gadget Driver,可以通过 configfs 文件系统,不用重新编译内核,动态的配置需要使用的 Function
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃秃秃秃哇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值