首页 > 系统相关 >Linux usb【4】- gadget configfs介绍

Linux usb【4】- gadget configfs介绍

时间:2025-01-22 19:01:06浏览次数:3  
标签:function configfs usb gadget name config struct

本文介绍如何通过configfs的方式创建一些usb设备, 我们以uac2设备为例介绍一下整个流程。

首先看一下driver/usb/gadget/function下的所有文件都是使用DECLARE_USB_FUNCTION_INIT注册一个usb_function_driver。

613  #define DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)		\
614  	static struct usb_function_driver _name ## usb_func = {		\
615  		.name = __stringify(_name),				\
616  		.mod  = THIS_MODULE,					\
617  		.alloc_inst = _inst_alloc,				\
618  		.alloc_func = _func_alloc,				\
619  	};								\
620  	MODULE_ALIAS("usbfunc:"__stringify(_name));
621  
622  #define DECLARE_USB_FUNCTION_INIT(_name, _inst_alloc, _func_alloc)	\
623  	DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)		\
624  	static int __init _name ## mod_init(void)			\
625  	{								\
626  		return usb_function_register(&_name ## usb_func);	\
627  	}								\
628  	static void __exit _name ## mod_exit(void)			\
629  	{								\
630  		usb_function_unregister(&_name ## usb_func);		\
631  	}								\
632  	module_init(_name ## mod_init);					\
633  	module_exit(_name ## mod_exit)

在usb_function_register中会将usb_function_driver挂载到func_list全局链表上。

91  int usb_function_register(struct usb_function_driver *newf)
92  {
93  	struct usb_function_driver *fd;
94  	int ret;
95  
96  	ret = -EEXIST;
97  
98  	mutex_lock(&func_lock);
99  	list_for_each_entry(fd, &func_list, list) {
100  		if (!strcmp(fd->name, newf->name))
101  			goto out;
102  	}
103  	ret = 0;
104  	list_add_tail(&newf->list, &func_list);
105  out:
106  	mutex_unlock(&func_lock);
107  	return ret;
108  }
109  EXPORT_SYMBOL_GPL(usb_function_register);

 f_uac2.c同样是通过DECLARE_USB_FUNCTION_INIT(uac2, afunc_alloc_inst, afunc_alloc)注册了一个uac2的driver到系统中。

我们再接着看一下drivers/usb/gadget/configfs.c这个文件,可以看到它注册了一个名字为usb_gadget的configfs_subsystem。configfs_subsystem最主要的成员其实就是一个config_group,可以看到config_group->config_item->config_item_type就是gadgets_type, gadgets_type的configfs_group_operations就是gadgets_ops。

1651  static struct configfs_group_operations gadgets_ops = {
1652  	.make_group     = &gadgets_make,
1653  	.drop_item      = &gadgets_drop,
1654  };
1655  
1656  static const struct config_item_type gadgets_type = {
1657  	.ct_group_ops   = &gadgets_ops,
1658  	.ct_owner       = THIS_MODULE,
1659  };
1660  
1661  static struct configfs_subsystem gadget_subsys = {
1662  	.su_group = {
1663  		.cg_item = {
1664  			.ci_namebuf = "usb_gadget",
1665  			.ci_type = &gadgets_type,
1666  		},
1667  	},
1668  	.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
1669  };
1670  
1671  void unregister_gadget_item(struct config_item *item)
1672  {
1673  	struct gadget_info *gi = to_gadget_info(item);
1674  
1675  	mutex_lock(&gi->lock);
1676  	unregister_gadget(gi);
1677  	mutex_unlock(&gi->lock);
1678  }
1679  EXPORT_SYMBOL_GPL(unregister_gadget_item);
1680  
1681  static int __init gadget_cfs_init(void)
1682  {
1683  	int ret;
1684  
1685  	config_group_init(&gadget_subsys.su_group);
1686  
1687  	ret = configfs_register_subsystem(&gadget_subsys);
1688  	return ret;
1689  }
1690  module_init(gadget_cfs_init);
1691  
1692  static void __exit gadget_cfs_exit(void)
1693  {
1694  	configfs_unregister_subsystem(&gadget_subsys);
1695  }
1696  module_exit(gadget_cfs_exit);

我们接着看一下这个uac2设备在用户态是如何被激活并使用的。

#!/bin/bash
function start_uac2()
{
	# usb_gadget依赖于libcomposite模块
	modprobe libcomposite
	# 挂载config文件系统
	mount -t configfs none /sys/kernel/config

	# 创建g1目录,实例化一个新的gadget模板
	
	echo "mkdir /sys/kernel/config/usb_gadget/g1"
	mkdir -m 0770 /sys/kernel/config/usb_gadget/g1

	# 设置产品的VendorID、ProductID及USB规范版本号
	echo "Setting Vendor Product ID's and bcdDevice"
	echo 0x2207 > /sys/kernel/config/usb_gadget/g1/idVendor
	echo 0x0019 > /sys/kernel/config/usb_gadget/g1/idProduct
	# 设备版本号
	echo 0x0200 > /sys/kernel/config/usb_gadget/g1/bcdDevice
	# USB 1.1: 0x0110
	# USB 2.0: 0x0200, USB 2.1: 0x0210, USB 2.5: 0x0250
	# USB 3.0: 0x0300, USB 3.1: 0x0310, USB 3.2: 0x0320
	# echo 0x0210 > /sys/kernel/config/usb_gadget/g1/bcdUSB
	
	# 实例化英语ID,开发商、产品和序列号字符串写入内核
	echo "Setting English strings"
	mkdir -m 0770 /sys/kernel/config/usb_gadget/g1/strings/0x409
	echo "0123456789ABCDEF" > /sys/kernel/config/usb_gadget/g1/strings/0x409/serialnumber
	echo "rockchip"  > /sys/kernel/config/usb_gadget/g1/strings/0x409/manufacturer
	echo "USB Audio Device"  > /sys/kernel/config/usb_gadget/g1/strings/0x409/product

	# Creating Config
	echo "Creating Config"
	mkdir -m 0770 /sys/kernel/config/usb_gadget/g1/configs/c.1
	mkdir -m 0770 /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
	echo "uac2" > /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409/configuration
	echo 500 > /sys/kernel/config/usb_gadget/g1/configs/c.1/MaxPower

	 
	# bind functions
	# uac2 need to put before uvc, otherwise uvc + uac2 enumerate failed in win10
	echo "Creating UAC2 gadget functionality : uac2.0"
	mkdir /sys/kernel/config/usb_gadget/g1/functions/uac2.0
	ln -s /sys/kernel/config/usb_gadget/g1/functions/uac2.0 /sys/kernel/config/usb_gadget/g1/configs/c.1

	# Binding USB Device Controller
	echo "Binding USB Device Controller"
	echo fe800000.dwc3 > /sys/kernel/config/usb_gadget/g1/UDC
}

function stop_uac2()
{
	# Disabling the gadget
	echo "Disabling the USB gadget"
	echo "" > /sys/kernel/config/usb_gadget/g1/UDC

	# Remove functions from configurations
	rm /sys/kernel/config/usb_gadget/g1/configs/c.1/uac2.0
	# Remove strings directories in configurations
	rmdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
	# remove the configurations
	rmdir /sys/kernel/config/usb_gadget/g1/configs/c.1

	# Remove functions (function modules are not unloaded, though)
	rmdir /sys/kernel/config/usb_gadget/g1/functions/uac2.0

	# Remove strings directories in the gadget
	rmdir /sys/kernel/config/usb_gadget/g1/strings/0x409

	# finally remove the gadget
	rmdir /sys/kernel/config/usb_gadget/g1
}

usage()
{
    echo "Usage: ./usb-gadget-uac2.sh start|stop"
    echo " options:"
    echo "    start           start uac2.0 gadget"
    echo "    stop            stop uac2.0 gadget"
}

case $1 in
start)
	start_uac2
	;;
stop)
	stop_uac2
	;;
*)
	usage
	exit 1
	;;
esac
exit 0

执行mkdir -m 0770 /sys/kernel/config/usb_gadget/g1后会执行gadgets_make回调,gadgets_make的第一参数就是usb_gadget这个configfs_subsystem对应的config_group,第二个参数就是"g1"。可以看到在sys/kernel/config/usb_gadget/g1这个config_group里面创建了好多的configfs_attribute 和config_group。这个函数还有分配一个gadget_info结构,这个gadget_info中保存了这个gadget设备的所有信息。

352  static struct configfs_attribute *gadget_root_attrs[] = {
353  	&gadget_dev_desc_attr_bDeviceClass,
354  	&gadget_dev_desc_attr_bDeviceSubClass,
355  	&gadget_dev_desc_attr_bDeviceProtocol,
356  	&gadget_dev_desc_attr_bMaxPacketSize0,
357  	&gadget_dev_desc_attr_idVendor,
358  	&gadget_dev_desc_attr_idProduct,
359  	&gadget_dev_desc_attr_bcdDevice,
360  	&gadget_dev_desc_attr_bcdUSB,
361  	&gadget_dev_desc_attr_UDC,
362  	&gadget_dev_desc_attr_max_speed,
363  	NULL,
364  };


564  static const struct config_item_type gadget_root_type = {
565  	.ct_item_ops	= &gadget_root_item_ops,
566  	.ct_attrs	= gadget_root_attrs,
567  	.ct_owner	= THIS_MODULE,
568  };


1588  static struct config_group *gadgets_make(
1589  		struct config_group *group,
1590  		const char *name)
1591  {
1592  	struct gadget_info *gi;
1593  
1594  	gi = kzalloc(sizeof(*gi), GFP_KERNEL);
1595  	if (!gi)
1596  		return ERR_PTR(-ENOMEM);
1597  
1598  	config_group_init_type_name(&gi->group, name, &gadget_root_type);
1599  
1600  	config_group_init_type_name(&gi->functions_group, "functions",
1601  			&functions_type);
1602  	configfs_add_default_group(&gi->functions_group, &gi->group);
1603  
1604  	config_group_init_type_name(&gi->configs_group, "configs",
1605  			&config_desc_type);
1606  	configfs_add_default_group(&gi->configs_group, &gi->group);
1607  
1608  	config_group_init_type_name(&gi->strings_group, "strings",
1609  			&gadget_strings_strings_type);
1610  	configfs_add_default_group(&gi->strings_group, &gi->group);
1611  
1612  	config_group_init_type_name(&gi->os_desc_group, "os_desc",
1613  			&os_desc_type);
1614  	configfs_add_default_group(&gi->os_desc_group, &gi->group);
1615  
1616  	gi->composite.bind = configfs_do_nothing;
1617  	gi->composite.unbind = configfs_do_nothing;
1618  	gi->composite.suspend = NULL;
1619  	gi->composite.resume = NULL;
1620  	gi->composite.max_speed = USB_SPEED_SUPER_PLUS;
1621  
1622  	spin_lock_init(&gi->spinlock);
1623  	mutex_init(&gi->lock);
1624  	INIT_LIST_HEAD(&gi->string_list);
1625  	INIT_LIST_HEAD(&gi->available_func);
1626  
1627  	composite_init_dev(&gi->cdev);
1628  	gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
1629  	gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
1630  	gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());
1631  
1632  	gi->composite.gadget_driver = configfs_driver_template;
1633  
1634  	gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
1635  	gi->composite.name = gi->composite.gadget_driver.function;
1636  
1637  	if (!gi->composite.gadget_driver.function)
1638  		goto err;
1639  
1640  	return &gi->group;
1641  err:
1642  	kfree(gi);
1643  	return ERR_PTR(-ENOMEM);
1644  }

我们可以看到gadet_info中包含一个复合设备结构usb_composite_dev 和一个复活设备驱动usb_composite_driver 。它们的初始化也是在gadgets_make中。

35  struct gadget_info {
36  	struct config_group group;
37  	struct config_group functions_group;
38  	struct config_group configs_group;
39  	struct config_group strings_group;
40  	struct config_group os_desc_group;
41  
42  	struct mutex lock;
43  	struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
44  	struct list_head string_list;
45  	struct list_head available_func;
46  
47  	struct usb_composite_driver composite;
48  	struct usb_composite_dev cdev;
49  	bool use_os_desc;
50  	char b_vendor_code;
51  	char qw_sign[OS_STRING_QW_SIGN_LEN];
52  	spinlock_t spinlock;
53  	bool unbind;
54  };

执行mkdir -m 0770 /sys/kernel/config/usb_gadget/g1/configs/c.1会执行config_desc_make回调。主要就是分配了一个config_usb_cfg 结构,调用config_group_init_type_name对config_usb_cfg ->config_group进行了初始化,初始的config_item_type为gadget_config_type。 并且调用usb_add_config_only函数,最后返回config_usb_cfg ->config_group。这个"c.1"后面的1就是配置描述符的id号。

671  static struct config_group *config_desc_make(
672  		struct config_group *group,
673  		const char *name)
674  {
675  	struct gadget_info *gi;
676  	struct config_usb_cfg *cfg;
677  	char buf[MAX_NAME_LEN];
678  	char *num_str;
679  	u8 num;
680  	int ret;
681  
682  	gi = container_of(group, struct gadget_info, configs_group);
683  	ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
684  	if (ret >= MAX_NAME_LEN)
685  		return ERR_PTR(-ENAMETOOLONG);
686  
687  	num_str = strchr(buf, '.');
688  	if (!num_str) {
689  		pr_err("Unable to locate . in name.bConfigurationValue\n");
690  		return ERR_PTR(-EINVAL);
691  	}
692  
693  	*num_str = '\0';
694  	num_str++;
695  
696  	if (!strlen(buf))
697  		return ERR_PTR(-EINVAL);
698  
699  	ret = kstrtou8(num_str, 0, &num);
700  	if (ret)
701  		return ERR_PTR(ret);
702  
703  	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
704  	if (!cfg)
705  		return ERR_PTR(-ENOMEM);
706  	cfg->c.label = kstrdup(buf, GFP_KERNEL);
707  	if (!cfg->c.label) {
708  		ret = -ENOMEM;
709  		goto err;
710  	}
711  	cfg->c.bConfigurationValue = num;
712  	cfg->c.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW;
713  	cfg->c.bmAttributes = USB_CONFIG_ATT_ONE;
714  	INIT_LIST_HEAD(&cfg->string_list);
715  	INIT_LIST_HEAD(&cfg->func_list);
716  
717  	config_group_init_type_name(&cfg->group, name,
718  				&gadget_config_type);
719  
720  	config_group_init_type_name(&cfg->strings_group, "strings",
721  			&gadget_config_name_strings_type);
722  	configfs_add_default_group(&cfg->strings_group, &cfg->group);
723  
724  	ret = usb_add_config_only(&gi->cdev, &cfg->c);
725  	if (ret)
726  		goto err;
727  
728  	return &cfg->group;
729  err:
730  	kfree(cfg->c.label);
731  	kfree(cfg);
732  	return ERR_PTR(ret);
733  }

gadget_config_type定义如下,重点关注的就是里面定义的configfs_item_operations为gadget_config_item_ops。

498  static struct configfs_item_operations gadget_config_item_ops = {
499  	.release                = gadget_config_attr_release,
500  	.allow_link             = config_usb_cfg_link,
501  	.drop_link              = config_usb_cfg_unlink,
502  };


558  static const struct config_item_type gadget_config_type = {
559  	.ct_item_ops	= &gadget_config_item_ops,
560  	.ct_attrs	= gadget_config_attrs,
561  	.ct_owner	= THIS_MODULE,
562  };

usb_add_config_only主要就是将config_usb_cfg->usb_configuration 结构挂到gadget_info->usb_composite_dev->configs链表上,同时将config_usb_cfg->usb_configuration->usb_composite_dev赋值为gadget_info->usb_composite_dev,并将这个配置描述符里的接口描述符清0。

960  int usb_add_config_only(struct usb_composite_dev *cdev,
961  		struct usb_configuration *config)
962  {
963  	struct usb_configuration *c;
964  
965  	if (!config->bConfigurationValue)
966  		return -EINVAL;
967  
968  	/* Prevent duplicate configuration identifiers */
969  	list_for_each_entry(c, &cdev->configs, list) {
970  		if (c->bConfigurationValue == config->bConfigurationValue)
971  			return -EBUSY;
972  	}
973  
974  	config->cdev = cdev;
975  	list_add_tail(&config->list, &cdev->configs);
976  
977  	INIT_LIST_HEAD(&config->functions);
978  	config->next_interface_id = 0;
979  	memset(config->interface, 0, sizeof(config->interface));
980  
981  	return 0;
982  }

执行mkdir /sys/kernel/config/usb_gadget/g1/functions/uac2.0后,会执行function_make回调。在function_make中主要是调用usb_get_function_instance获取usb_function_instance,调用config_item_set_name将fusb_function_instance>config_group->config_item的name设置为"uac2.0",然后将这个usb_get_function_instance挂载到gadget_info的available_func链表上,最后返回了usb_get_function_instance->config_group。

577  static struct config_group *function_make(
578  		struct config_group *group,
579  		const char *name)
580  {
581  	struct gadget_info *gi;
582  	struct usb_function_instance *fi;
583  	char buf[MAX_NAME_LEN];
584  	char *func_name;
585  	char *instance_name;
586  	int ret;
587  
588  	ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
589  	if (ret >= MAX_NAME_LEN)
590  		return ERR_PTR(-ENAMETOOLONG);
591  
592  	func_name = buf;
593  	instance_name = strchr(func_name, '.');
594  	if (!instance_name) {
595  		pr_err("Unable to locate . in FUNC.INSTANCE\n");
596  		return ERR_PTR(-EINVAL);
597  	}
598  	*instance_name = '\0';
599  	instance_name++;
600  
601  	fi = usb_get_function_instance(func_name);
602  	if (IS_ERR(fi))
603  		return ERR_CAST(fi);
604  
605  	ret = config_item_set_name(&fi->group.cg_item, "%s", name);
606  	if (ret) {
607  		usb_put_function_instance(fi);
608  		return ERR_PTR(ret);
609  	}
610  	if (fi->set_inst_name) {
611  		ret = fi->set_inst_name(fi, instance_name);
612  		if (ret) {
613  			usb_put_function_instance(fi);
614  			return ERR_PTR(ret);
615  		}
616  	}
617  
618  	gi = container_of(group, struct gadget_info, functions_group);
619  
620  	mutex_lock(&gi->lock);
621  	list_add_tail(&fi->cfs_list, &gi->available_func);
622  	mutex_unlock(&gi->lock);
623  	return &fi->group;
624  }

usb_get_function_instance最终会调用到try_get_usb_function_instance,在func_list链表中找到对应的usb_function_driver,在调用usb_function_driver里的alloc_inst回调。

12  static struct usb_function_instance *try_get_usb_function_instance(const char *name)
13  {
14  	struct usb_function_driver *fd;
15  	struct usb_function_instance *fi;
16  
17  	fi = ERR_PTR(-ENOENT);
18  	mutex_lock(&func_lock);
19  	list_for_each_entry(fd, &func_list, list) {
20  
21  		if (strcmp(name, fd->name))
22  			continue;
23  
24  		if (!try_module_get(fd->mod)) {
25  			fi = ERR_PTR(-EBUSY);
26  			break;
27  		}
28  		fi = fd->alloc_inst();
29  		if (IS_ERR(fi))
30  			module_put(fd->mod);
31  		else
32  			fi->fd = fd;
33  		break;
34  	}
35  	mutex_unlock(&func_lock);
36  	return fi;
37  }

uac2.0的alloc_inst回调就是afunc_alloc_inst,在afunc_alloc_inst主要就是申请了f_uac2_opts结构,f_uac2_opts里包含了usb_function_instance,usb_function_instance又包含了一个config_group结构,使用config_group_init_type_name对这个config_group结构进行了初始化, 添加了相关的属性文件,这个config_group就是用来对不同的funcution进行配置的。

2109  static struct configfs_attribute *f_uac2_attrs[] = {
2110  	&f_uac2_opts_attr_p_chmask,
2111  	&f_uac2_opts_attr_p_srate,
2112  	&f_uac2_opts_attr_p_ssize,
2113  	&f_uac2_opts_attr_p_hs_bint,
2114  	&f_uac2_opts_attr_c_chmask,
2115  	&f_uac2_opts_attr_c_srate,
2116  	&f_uac2_opts_attr_c_ssize,
2117  	&f_uac2_opts_attr_c_hs_bint,
2118  	&f_uac2_opts_attr_c_sync,
2119  	&f_uac2_opts_attr_req_number,
2120  	&f_uac2_opts_attr_fb_max,
2121  
2122  	&f_uac2_opts_attr_p_mute_present,
2123  	&f_uac2_opts_attr_p_volume_present,
2124  	&f_uac2_opts_attr_p_volume_min,
2125  	&f_uac2_opts_attr_p_volume_max,
2126  	&f_uac2_opts_attr_p_volume_res,
2127  
2128  	&f_uac2_opts_attr_c_mute_present,
2129  	&f_uac2_opts_attr_c_volume_present,
2130  	&f_uac2_opts_attr_c_volume_min,
2131  	&f_uac2_opts_attr_c_volume_max,
2132  	&f_uac2_opts_attr_c_volume_res,
2133  
2134  	&f_uac2_opts_attr_function_name,
2135  
2136  	NULL,
2137  };
2138  
2139  static const struct config_item_type f_uac2_func_type = {
2140  	.ct_item_ops	= &f_uac2_item_ops,
2141  	.ct_attrs	= f_uac2_attrs,
2142  	.ct_owner	= THIS_MODULE,
2143  };


2153  static struct usb_function_instance *afunc_alloc_inst(void)
2154  {
2155  	struct f_uac2_opts *opts;
2156  
2157  	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
2158  	if (!opts)
2159  		return ERR_PTR(-ENOMEM);
2160  
2161  	mutex_init(&opts->lock);
2162  	opts->func_inst.free_func_inst = afunc_free_inst;
2163  
2164  	config_group_init_type_name(&opts->func_inst.group, "",
2165  				    &f_uac2_func_type);
2166  
2167  	opts->p_chmask = UAC2_DEF_PCHMASK;
2168  	opts->p_srates[0] = UAC2_DEF_PSRATE;
2169  	opts->p_ssize = UAC2_DEF_PSSIZE;
2170  	opts->p_hs_bint = UAC2_DEF_PHSBINT;
2171  	opts->c_chmask = UAC2_DEF_CCHMASK;
2172  	opts->c_srates[0] = UAC2_DEF_CSRATE;
2173  	opts->c_ssize = UAC2_DEF_CSSIZE;
2174  	opts->c_hs_bint = UAC2_DEF_CHSBINT;
2175  	opts->c_sync = UAC2_DEF_CSYNC;
2176  
2177  	opts->p_mute_present = UAC2_DEF_MUTE_PRESENT;
2178  	opts->p_volume_present = UAC2_DEF_VOLUME_PRESENT;
2179  	opts->p_volume_min = UAC2_DEF_MIN_DB;
2180  	opts->p_volume_max = UAC2_DEF_MAX_DB;
2181  	opts->p_volume_res = UAC2_DEF_RES_DB;
2182  
2183  	opts->c_mute_present = UAC2_DEF_MUTE_PRESENT;
2184  	opts->c_volume_present = UAC2_DEF_VOLUME_PRESENT;
2185  	opts->c_volume_min = UAC2_DEF_MIN_DB;
2186  	opts->c_volume_max = UAC2_DEF_MAX_DB;
2187  	opts->c_volume_res = UAC2_DEF_RES_DB;
2188  
2189  	opts->req_number = UAC2_DEF_REQ_NUM;
2190  	opts->fb_max = FBACK_FAST_MAX;
2191  
2192  	snprintf(opts->function_name, sizeof(opts->function_name), "Source/Sink");
2193  
2194  	return &opts->func_inst;
2195  }

执行ln -s /sys/kernel/config/usb_gadget/g1/functions/uac2.0 /sys/kernel/config/usb_gadget/g1/configs/c.1后,会调用到config_usb_cfg_link。在config_usb_cfg_link里,调用usb_get_function得到usb_function结构,并挂载到config_usb_cfg的func_list链表上。

411  static int config_usb_cfg_link(
412  	struct config_item *usb_cfg_ci,
413  	struct config_item *usb_func_ci)
414  {
415  	struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
416  	struct usb_composite_dev *cdev = cfg->c.cdev;
417  	struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
418  
419  	struct config_group *group = to_config_group(usb_func_ci);
420  	struct usb_function_instance *fi = container_of(group,
421  			struct usb_function_instance, group);
422  	struct usb_function_instance *a_fi;
423  	struct usb_function *f;
424  	int ret;
425  
426  	mutex_lock(&gi->lock);
427  	/*
428  	 * Make sure this function is from within our _this_ gadget and not
429  	 * from another gadget or a random directory.
430  	 * Also a function instance can only be linked once.
431  	 */
432  	list_for_each_entry(a_fi, &gi->available_func, cfs_list) {
433  		if (a_fi == fi)
434  			break;
435  	}
436  	if (a_fi != fi) {
437  		ret = -EINVAL;
438  		goto out;
439  	}
440  
441  	list_for_each_entry(f, &cfg->func_list, list) {
442  		if (f->fi == fi) {
443  			ret = -EEXIST;
444  			goto out;
445  		}
446  	}
447  
448  	f = usb_get_function(fi);
449  	if (IS_ERR(f)) {
450  		ret = PTR_ERR(f);
451  		goto out;
452  	}
453  
454  	/* stash the function until we bind it to the gadget */
455  	list_add_tail(&f->list, &cfg->func_list);
456  	ret = 0;
457  out:
458  	mutex_unlock(&gi->lock);
459  	return ret;
460  }

usb_get_function主要是调用afunc_alloc回调,创建usb_funciton结构,初始化后返回。

57  struct usb_function *usb_get_function(struct usb_function_instance *fi)
58  {
59  	struct usb_function *f;
60  
61  	f = fi->fd->alloc_func(fi);
62  	if (IS_ERR(f))
63  		return f;
64  	f->fi = fi;
65  	return f;
66  }


2225  static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
2226  {
2227  	struct f_uac2	*uac2;
2228  	struct f_uac2_opts *opts;
2229  
2230  	uac2 = kzalloc(sizeof(*uac2), GFP_KERNEL);
2231  	if (uac2 == NULL)
2232  		return ERR_PTR(-ENOMEM);
2233  
2234  	opts = container_of(fi, struct f_uac2_opts, func_inst);
2235  	mutex_lock(&opts->lock);
2236  	++opts->refcnt;
2237  	mutex_unlock(&opts->lock);
2238  
2239  	uac2->g_audio.func.name = "uac2_func";
2240  	uac2->g_audio.func.bind = afunc_bind;
2241  	uac2->g_audio.func.unbind = afunc_unbind;
2242  	uac2->g_audio.func.set_alt = afunc_set_alt;
2243  	uac2->g_audio.func.get_alt = afunc_get_alt;
2244  	uac2->g_audio.func.disable = afunc_disable;
2245  	uac2->g_audio.func.suspend = afunc_suspend;
2246  	uac2->g_audio.func.setup = afunc_setup;
2247  	uac2->g_audio.func.free_func = afunc_free;
2248  
2249  	return &uac2->g_audio.func;
2250  }

我们看下CONFIGFS_ATTR的定义

123  #define CONFIGFS_ATTR(_pfx, _name)			\
124  static struct configfs_attribute _pfx##attr_##_name = {	\
125  	.ca_name	= __stringify(_name),		\
126  	.ca_mode	= S_IRUGO | S_IWUSR,		\
127  	.ca_owner	= THIS_MODULE,			\
128  	.show		= _pfx##_name##_show,		\
129  	.store		= _pfx##_name##_store,		\
130  }

根据上面CONFIGFS_ATTR的定义可以看出,执行echo fe800000.dwc3 > /sys/kernel/config/usb_gadget/g1/UDC后会调用gadget_dev_desc_UDC_store函数,在这个函数中会调用usb_gadget_probe_driver,probe一个gadget driver,根据前面的分析这个gadget driver就是configfs_driver_template。

1569  static const struct usb_gadget_driver configfs_driver_template = {
1570  	.bind           = configfs_composite_bind,
1571  	.unbind         = configfs_composite_unbind,
1572  
1573  	.setup          = configfs_composite_setup,
1574  	.reset          = configfs_composite_reset,
1575  	.disconnect     = configfs_composite_disconnect,
1576  
1577  	.suspend	= configfs_composite_suspend,
1578  	.resume		= configfs_composite_resume,
1579  
1580  	.max_speed	= USB_SPEED_SUPER_PLUS,
1581  	.driver = {
1582  		.owner          = THIS_MODULE,
1583  		.name		= "configfs-gadget",
1584  	},
1585  	.match_existing_only = 1,
1586  };


257  static ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
258  		const char *page, size_t len)
259  {
260  	struct gadget_info *gi = to_gadget_info(item);
261  	char *name;
262  	int ret;
263  
264  	if (strlen(page) < len)
265  		return -EOVERFLOW;
266  
267  	name = kstrdup(page, GFP_KERNEL);
268  	if (!name)
269  		return -ENOMEM;
270  	if (name[len - 1] == '\n')
271  		name[len - 1] = '\0';
272  
273  	mutex_lock(&gi->lock);
274  
275  	if (!strlen(name)) {
276  		ret = unregister_gadget(gi);
277  		if (ret)
278  			goto err;
279  		kfree(name);
280  	} else {
281  		if (gi->composite.gadget_driver.udc_name) {
282  			ret = -EBUSY;
283  			goto err;
284  		}
285  		gi->composite.gadget_driver.udc_name = name;
286  		ret = usb_gadget_probe_driver(&gi->composite.gadget_driver);
287  		if (ret) {
288  			gi->composite.gadget_driver.udc_name = NULL;
289  			goto err;
290  		}
291  	}
292  	mutex_unlock(&gi->lock);
293  	return len;
294  err:
295  	kfree(name);
296  	mutex_unlock(&gi->lock);
297  	return ret;
298  }

usb_gadget_probe_driver里面主要就是同过udc_name,从udc_list链表里面找到对应的usb_udc。udc_list我们在前面的文章介绍过,上面会挂载所有的udc控制器设备,我们前面文章也介绍过在device_add时没有给它匹配驱动,是在usb_gadget_probe_driver中通过udc_bind_to_driver绑定的驱动。

1524  int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
1525  {
1526  	struct usb_udc		*udc = NULL;
1527  	int			ret = -ENODEV;
1528  
1529  	if (!driver || !driver->bind || !driver->setup)
1530  		return -EINVAL;
1531  
1532  	mutex_lock(&udc_lock);
1533  	if (driver->udc_name) {
1534  		list_for_each_entry(udc, &udc_list, list) {
1535  			ret = strcmp(driver->udc_name, dev_name(&udc->dev));
1536  			if (!ret)
1537  				break;
1538  		}
1539  		if (ret)
1540  			ret = -ENODEV;
1541  		else if (udc->driver)
1542  			ret = -EBUSY;
1543  		else
1544  			goto found;
1545  	} else {
1546  		list_for_each_entry(udc, &udc_list, list) {
1547  			/* For now we take the first one */
1548  			if (!udc->driver)
1549  				goto found;
1550  		}
1551  	}
1552  
1553  	if (!driver->match_existing_only) {
1554  		list_add_tail(&driver->pending, &gadget_driver_pending_list);
1555  		pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
1556  			driver->function);
1557  		ret = 0;
1558  	}
1559  
1560  	mutex_unlock(&udc_lock);
1561  	if (ret)
1562  		pr_warn("udc-core: couldn't find an available UDC or it's busy\n");
1563  	return ret;
1564  found:
1565  	ret = udc_bind_to_driver(udc, driver);
1566  	mutex_unlock(&udc_lock);
1567  	return ret;
1568  }

udc_bind_to_driver中除了 调用udc->gadget->dev.driver = &driver->driver将device和device_driver绑定到一起,还会调用usb_gadget_drive里的bind回调。这个函数做的事情比较多, 我们后面一条条的分析。

1490  static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *driver)
1491  {
1492  	int ret;
1493  
1494  	dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
1495  			driver->function);
1496  
1497  	udc->driver = driver;
1498  	udc->gadget->dev.driver = &driver->driver;
1499  
1500  	usb_gadget_udc_set_speed(udc, driver->max_speed);
1501  
1502  	ret = driver->bind(udc->gadget, driver);
1503  	if (ret)
1504  		goto err1;
1505  	ret = usb_gadget_udc_start(udc);
1506  	if (ret) {
1507  		driver->unbind(udc->gadget);
1508  		goto err1;
1509  	}
1510  	usb_gadget_enable_async_callbacks(udc);
1511  	usb_udc_connect_control(udc);
1512  
1513  	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
1514  	return 0;
1515  err1:
1516  	if (ret != -EISNAM)
1517  		dev_err(&udc->dev, "failed to start %s: %d\n",
1518  			udc->driver->function, ret);
1519  	udc->driver = NULL;
1520  	udc->gadget->dev.driver = NULL;
1521  	return ret;
1522  }

bind回调其实就是configfs_composite_bind,configfs_composite_bind主要作用就是遍历usb_composite_dev里的所有usb_configuration,然后再遍历usb_configuration对应的所有usb_function,最后调用usb_add_function把usb_configuration和下面所有的usb_function绑定到一起。

1283  static int configfs_composite_bind(struct usb_gadget *gadget,
1284  		struct usb_gadget_driver *gdriver)
1285  {
1286  	struct usb_composite_driver     *composite = to_cdriver(gdriver);
1287  	struct gadget_info		*gi = container_of(composite,
1288  						struct gadget_info, composite);
1289  	struct usb_composite_dev	*cdev = &gi->cdev;
1290  	struct usb_configuration	*c;
1291  	struct usb_string		*s;
1292  	unsigned			i;
1293  	int				ret;
1294  
1295  	/* the gi->lock is hold by the caller */
1296  	gi->unbind = 0;
1297  	cdev->gadget = gadget;
1298  	set_gadget_data(gadget, cdev);
1299  	ret = composite_dev_prepare(composite, cdev);
1300  	if (ret)
1301  		return ret;
1302  	/* and now the gadget bind */
1303  	ret = -EINVAL;
1304  
1305  	if (list_empty(&gi->cdev.configs)) {
1306  		pr_err("Need at least one configuration in %s.\n",
1307  				gi->composite.name);
1308  		goto err_comp_cleanup;
1309  	}
1310  
1311  
1312  	list_for_each_entry(c, &gi->cdev.configs, list) {
1313  		struct config_usb_cfg *cfg;
1314  
1315  		cfg = container_of(c, struct config_usb_cfg, c);
1316  		if (list_empty(&cfg->func_list)) {
1317  			pr_err("Config %s/%d of %s needs at least one function.\n",
1318  			      c->label, c->bConfigurationValue,
1319  			      gi->composite.name);
1320  			goto err_comp_cleanup;
1321  		}
1322  	}
1323  
1324  	/* init all strings */
1325  	if (!list_empty(&gi->string_list)) {
1326  		struct gadget_strings *gs;
1327  
1328  		i = 0;
1329  		list_for_each_entry(gs, &gi->string_list, list) {
1330  
1331  			gi->gstrings[i] = &gs->stringtab_dev;
1332  			gs->stringtab_dev.strings = gs->strings;
1333  			gs->strings[USB_GADGET_MANUFACTURER_IDX].s =
1334  				gs->manufacturer;
1335  			gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product;
1336  			gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber;
1337  			i++;
1338  		}
1339  		gi->gstrings[i] = NULL;
1340  		s = usb_gstrings_attach(&gi->cdev, gi->gstrings,
1341  				USB_GADGET_FIRST_AVAIL_IDX);
1342  		if (IS_ERR(s)) {
1343  			ret = PTR_ERR(s);
1344  			goto err_comp_cleanup;
1345  		}
1346  
1347  		gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
1348  		gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
1349  		gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
1350  	}
1351  
1352  	if (gi->use_os_desc) {
1353  		cdev->use_os_string = true;
1354  		cdev->b_vendor_code = gi->b_vendor_code;
1355  		memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN);
1356  	}
1357  
1358  	if (gadget_is_otg(gadget) && !otg_desc[0]) {
1359  		struct usb_descriptor_header *usb_desc;
1360  
1361  		usb_desc = usb_otg_descriptor_alloc(gadget);
1362  		if (!usb_desc) {
1363  			ret = -ENOMEM;
1364  			goto err_comp_cleanup;
1365  		}
1366  		usb_otg_descriptor_init(gadget, usb_desc);
1367  		otg_desc[0] = usb_desc;
1368  		otg_desc[1] = NULL;
1369  	}
1370  
1371  	/* Go through all configs, attach all functions */
1372  	list_for_each_entry(c, &gi->cdev.configs, list) {
1373  		struct config_usb_cfg *cfg;
1374  		struct usb_function *f;
1375  		struct usb_function *tmp;
1376  		struct gadget_config_name *cn;
1377  
1378  		if (gadget_is_otg(gadget))
1379  			c->descriptors = otg_desc;
1380  
1381  		cfg = container_of(c, struct config_usb_cfg, c);
1382  		if (!list_empty(&cfg->string_list)) {
1383  			i = 0;
1384  			list_for_each_entry(cn, &cfg->string_list, list) {
1385  				cfg->gstrings[i] = &cn->stringtab_dev;
1386  				cn->stringtab_dev.strings = &cn->strings;
1387  				cn->strings.s = cn->configuration;
1388  				i++;
1389  			}
1390  			cfg->gstrings[i] = NULL;
1391  			s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1);
1392  			if (IS_ERR(s)) {
1393  				ret = PTR_ERR(s);
1394  				goto err_comp_cleanup;
1395  			}
1396  			c->iConfiguration = s[0].id;
1397  		}
1398  
1399  		list_for_each_entry_safe(f, tmp, &cfg->func_list, list) {
1400  			list_del(&f->list);
1401  			ret = usb_add_function(c, f);
1402  			if (ret) {
1403  				list_add(&f->list, &cfg->func_list);
1404  				goto err_purge_funcs;
1405  			}
1406  		}
1407  		ret = usb_gadget_check_config(cdev->gadget);
1408  		if (ret)
1409  			goto err_purge_funcs;
1410  
1411  		usb_ep_autoconfig_reset(cdev->gadget);
1412  	}
1413  	if (cdev->use_os_string) {
1414  		ret = composite_os_desc_req_prepare(cdev, gadget->ep0);
1415  		if (ret)
1416  			goto err_purge_funcs;
1417  	}
1418  
1419  	usb_ep_autoconfig_reset(cdev->gadget);
1420  	return 0;
1421  
1422  err_purge_funcs:
1423  	purge_configs_funcs(gi);
1424  err_comp_cleanup:
1425  	composite_dev_cleanup(cdev);
1426  	return ret;
1427  }

usb_add_function这个函数主要就是调用了value = function->bind(config, function)这个回调。对应uac2设备就是afunc_bind。afunc_bind的主要作用就是填充各种描述符,调用usb_ep_autoconfig分配ep,然后调用g_audio_setup函数创建音频设备,这里就不贴代码了。

287  /**
288   * usb_add_function() - add a function to a configuration
289   * @config: the configuration
290   * @function: the function being added
291   * Context: single threaded during gadget setup
292   *
293   * After initialization, each configuration must have one or more
294   * functions added to it.  Adding a function involves calling its @bind()
295   * method to allocate resources such as interface and string identifiers
296   * and endpoints.
297   *
298   * This function returns the value of the function's bind(), which is
299   * zero for success else a negative errno value.
300   */
301  int usb_add_function(struct usb_configuration *config,
302  		struct usb_function *function)
303  {
304  	int	value = -EINVAL;
305  
306  	DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
307  			function->name, function,
308  			config->label, config);
309  
310  	if (!function->set_alt || !function->disable)
311  		goto done;
312  
313  	function->config = config;
314  	list_add_tail(&function->list, &config->functions);
315  
316  	if (function->bind_deactivated) {
317  		value = usb_function_deactivate(function);
318  		if (value)
319  			goto done;
320  	}
321  
322  	/* REVISIT *require* function->bind? */
323  	if (function->bind) {
324  		value = function->bind(config, function);
325  		if (value < 0) {
326  			list_del(&function->list);
327  			function->config = NULL;
328  		}
329  	} else
330  		value = 0;
331  
332  	/* We allow configurations that don't work at both speeds.
333  	 * If we run into a lowspeed Linux system, treat it the same
334  	 * as full speed ... it's the function drivers that will need
335  	 * to avoid bulk and ISO transfers.
336  	 */
337  	if (!config->fullspeed && function->fs_descriptors)
338  		config->fullspeed = true;
339  	if (!config->highspeed && function->hs_descriptors)
340  		config->highspeed = true;
341  	if (!config->superspeed && function->ss_descriptors)
342  		config->superspeed = true;
343  	if (!config->superspeed_plus && function->ssp_descriptors)
344  		config->superspeed_plus = true;
345  
346  done:
347  	if (value)
348  		DBG(config->cdev, "adding '%s'/%p --> %d\n",
349  				function->name, function, value);
350  	return value;
351  }
352  EXPORT_SYMBOL_GPL(usb_add_function);
353  
354  void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
355  {
356  	if (f->disable)
357  		f->disable(f);
358  
359  	bitmap_zero(f->endpoints, 32);
360  	list_del(&f->list);
361  	if (f->unbind)
362  		f->unbind(c, f);
363  
364  	if (f->bind_deactivated)
365  		usb_function_activate(f);
366  }

usb_ep_autoconfig内部会调用usb_ep_autoconfig_ss,在 usb_ep_autoconfig_ss中gadget->ops->match_ep dwc3的gadget驱动没有实现,所以会通过端口描述符找一个没有使用的ep。有了这个usb_ep结构,uac2驱动就可以使用它进行数据收发了。

63  struct usb_ep *usb_ep_autoconfig_ss(
64  	struct usb_gadget		*gadget,
65  	struct usb_endpoint_descriptor	*desc,
66  	struct usb_ss_ep_comp_descriptor *ep_comp
67  )
68  {
69  	struct usb_ep	*ep;
70  
71  	if (gadget->ops->match_ep) {
72  		ep = gadget->ops->match_ep(gadget, desc, ep_comp);
73  		if (ep)
74  			goto found_ep;
75  	}
76  
77  	/* Second, look at endpoints until an unclaimed one looks usable */
78  	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
79  		if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp))
80  			goto found_ep;
81  	}
82  
83  	/* Fail */
84  	return NULL;
85  found_ep:
86  
87  	/*
88  	 * If the protocol driver hasn't yet decided on wMaxPacketSize
89  	 * and wants to know the maximum possible, provide the info.
90  	 */
91  	if (desc->wMaxPacketSize == 0)
92  		desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);
93  
94  	/* report address */
95  	desc->bEndpointAddress &= USB_DIR_IN;
96  	if (isdigit(ep->name[2])) {
97  		u8 num = simple_strtoul(&ep->name[2], NULL, 10);
98  		desc->bEndpointAddress |= num;
99  	} else if (desc->bEndpointAddress & USB_DIR_IN) {
100  		if (++gadget->in_epnum > 15)
101  			return NULL;
102  		desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
103  	} else {
104  		if (++gadget->out_epnum > 15)
105  			return NULL;
106  		desc->bEndpointAddress |= gadget->out_epnum;
107  	}
108  
109  	ep->address = desc->bEndpointAddress;
110  	ep->desc = NULL;
111  	ep->comp_desc = NULL;
112  	ep->claimed = true;
113  	return ep;
114  }

 接着看udc_bind_to_driver函数,继续调用usb_gadget_udc_start, 里面其实主要就是调用了dwc3_gadget_start回调,在dwc3_gadget_start里主要就是注册了dwc3中断处理函数。后面继续调用usb_udc_connect_control函数,在usb_udc_connect_control函数里主要会调用到dwc3_gadget_pullup回调,在dwc3_gadget_pullup中就开始枚举流程了。

我们就介绍这么多,可以看到尽管我们尽量忽略一些细节介绍梗概,但是流程还是太复杂了。我后面再简单总结一下整个过程。

1.设备控制器驱动使用usb_gadget来抽象一个USB设备控制器硬件,使用usb_gadget_ops来实现对设备控制器的配置,使用usb_ep_ops实现实际的数据收发工作。

2.使用usb_gadget_driver 来抽象一个USB设备控制器的驱动,外界对这个设备控制器的管理就是通过这个驱动实现的。

3.使用usb_composite_dev来抽象一个复合设备,这个符合设备下会有多个usb_configuration ,每个usb_configuration 下又会有多个usb_funciton。function对应的是接口描述符,每个fuction会分配实际的usb_ep,function的具体功能就是通过这些ep实现的。

标签:function,configfs,usb,gadget,name,config,struct
From: https://blog.csdn.net/liverdream/article/details/145286088

相关文章

  • Linux usb【3】- gadget驱动介绍
    本文基于新思的dwc3usb控制器,介绍usb的gadget驱动,kernel版本为5.15。probe刚开始和前面介绍的host驱动是一样的,只不过在dwc3_core_init_mode函数中会选择gadget初始化dwc3_gadget_init。1214 staticintdwc3_core_init_mode(structdwc3*dwc)1215 {1216  structd......
  • OpenWRT24.10旁路由挂载USB移动硬盘,配置Samba4,作为NAS使用,解决中文不显示,乱码,解决断电
    1.为何选择OpenWRT24.10,及如何配置旁路由,或者IPv6地址看这篇:参OpenWRT24.10配置作为旁路由,并配置获取IPv4和IPv6地址使用的OpenWRT固件是从这里下载的:https://openwrt.ai/2.挂载大容量USB移动硬盘2.1安装必备插件kmod-fs-ntfs3kmod-fs-ext4kmod-fs-exfat#根据自己的......
  • RADXA 5B 开启 USB OTG 网络(虚拟网卡)
    RADXA5B开启USBOTG网络(虚拟网卡)按照官方文档进行配置,会不成功确保USB-A接口主板上,插入USB3.0下方接口(按着主板)配置设备树Overlays打开系统配置工具sudorsetup依次选择Overlays->警告Yes->Manageoverlays->空格选中SetOTGport1toPeriphe......
  • Silicon Labs C8051F020 单片机 USB Debug Adapter适配器调试无法连接问题
    在做单片机大作业,使用Keil,使用USB连接开发板。想要进入到调试或烧录功能时总是报错:CannotconnecttotheselectedUSBdebugadapterToolStickbaseadapter.Pleasecheckthatthedeviceispluggedinandnotalreadyinuse如图:首先按照老师发的教程逐个复查,排除了驱......
  • USB接口颜色都代表什么含义
    手机充电器人人都有!充电器线颜色都不同!你知道不同颜色的USB接口的各个颜色都代表什么含义吗?大部分人都是不知道的,这篇文章让您一目了然!建议收藏备用!以备不时之需!           ......
  • linux usb 驱动 - hcd 驱动框架
    linuxusbhcd驱动框架一、USB描述符1.数据结构1.1设备描述符1.2配置描述符1.3接口描述符1.4端点描述符1.5usb_hub_descriptor1.5usb_host_config1.6usb_interface_cache1.7usb_host_interface1.8usb_host_endpoint2.描述符的构建二、usb设备驱动管理1.......
  • 【Linux运维】如何在Linux中列出USB设备
    Linux操作系统提供了许多命令来列出系统中连接的USB设备。这些命令非常有用,无论是查看已连接设备的信息还是进行系统调试。在本文中,我们将介绍一些常用的命令以及它们的使用方法,帮助你了解如何在Linux中列出USB设备。1、lsusb命令lsusb命令是列出USB设备信息的常用命令。它会显......
  • Sigrity System SI SerialLink模式进行USB3.1协议仿真分析操作指导-SuperSpeedPlus_Rx
    SigritySystemSISerialLink模式进行USB3.1协议仿真分析操作指导-SuperSpeedPlus_Rx_HostSigritySystemSISerialLink模式提供了10个协议合规性检查工具模板,用户可以将根据实际应用替换模板中的SPICE文件,然后进行协议仿真分析,同时软件还提供了目标结果的模板MASK以及该协......
  • STM32单片机芯片与内部75 USB虚拟串口 标准库 HAL库 配置实现
    目录一、标准库工程1、USB初始化2、USB中断配置3、中断服务函数与回调接收4、USB连接5、时钟配置6、数据发送二、HAL库工程1、USB初始化2、中断服务函数与回调接收4、USB连接5、时钟配置6、数据发送一、标准库工程1、USB初始化    由官方进行适配。v......
  • STM32单片机芯片与内部74 USB 简介 控制器 通用寄存器 端点寄存器 缓冲区描述表
    目录一、USB简介二、STM32USB控制器三、通用寄存器1、USB控制寄存器(USB_CNTR)2、USB中断状态寄存器(USB_ISTR)3、USB帧编号寄存器(USB_FNR)5、USB设备地址寄存器(USB_DADDR)6、USB分组缓冲区描述表地址寄存器(USB_BTABLE)四、端点寄存器1、USB端点n寄存器(USB_EP......