本文介绍如何通过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