Linux usb【4】- gadget configfs介绍

本文介绍如何通过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->func
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值