如何让Linux FunctionFS USB Gadget在Windows10中识别为WINUSB设备?
问题:BeagleBone Blue USB FunctionFS WINUSB设备识别失败
我正尝试将BeagleBone Blue开发板制作成可与Windows主机通信的小型USB设备。编写了开机自动运行的Shell脚本配置FunctionFS Gadget,脚本内容如下:
#!/bin/bash sudo modprobe usb_f_fs cd /sys/kernel/config/usb_gadget/ sudo mkdir -p g_my_gadget cd g_my_gadget echo 0x0200 > bcdUSB # Complies with USB specification 2.0.0 echo 0xXXXX > idVendor # VID echo 0xXXXX > idProduct # PID echo 0x0100 > bcdDevice # v1.0.0 # String descriptors (configure these before you need them) sudo mkdir -p strings/0x0409 # 0x0409 is the code for English echo "SERIALNUMBER" > strings/0x0409/serialnumber echo "MY_MANUFACTURER" > strings/0x0409/manufacturer echo "MY DEVICE" > strings/0x0409/product # Configuration descriptor 1 sudo mkdir -p configs/c.1/strings/0x0409 echo "My Configuration" > configs/c.1/strings/0x0409/configuration # This sets iConfiguration in Configuration Descriptor echo 250 > configs/c.1/MaxPower # Request 500 mA echo 0xc0 > configs/c.1/bmAttributes echo 0x00 > bDeviceClass echo 0x00 > bDeviceSubClass echo 0x00 > bDeviceProtocol # Write OS Descriptors echo 1 > os_desc/use echo 0xcd > os_desc/b_vendor_code echo MSFT100 > os_desc/qw_sign sudo mkdir -p functions/ffs.usb0 # Calls *_alloc_inst in the kernel module--we can now set functions specific to the class sudo ln -s functions/ffs.usb0 configs/c.1/ # calls _alloc in the kernel module # Make the directory that the endpoints will live in + mount to the functionFS file system sudo mkdir /dev/ffs-usb0 sudo mount -t functionfs usb0 /dev/ffs-usb0
同时,拷贝了ffs-test.c并更新了描述符对象,编译后的二进制文件在脚本运行后执行,更新后的描述符如下:
.header = { .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2), .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC | FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC ), .length = cpu_to_le32(sizeof descriptors), }, .fs_count = cpu_to_le32(3), .fs_descs = { .intf = { .bLength = sizeof descriptors.fs_descs.intf, .bDescriptorType = USB_DT_INTERFACE, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 0xFF, .bInterfaceProtocol = 0xFF, .iInterface = 0, }, .sink = { .bLength = sizeof descriptors.fs_descs.sink, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 1 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, /* .wMaxPacketSize = autoconfiguration (kernel) */ }, .source = { .bLength = sizeof descriptors.fs_descs.source, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 2 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, /* .wMaxPacketSize = autoconfiguration (kernel) */ }, }, .hs_count = cpu_to_le32(3), .hs_descs = { .intf = { .bLength = sizeof descriptors.fs_descs.intf, .bDescriptorType = USB_DT_INTERFACE, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 0xFF, .bInterfaceProtocol = 0xFF, .iInterface = 0, }, .sink = { .bLength = sizeof descriptors.hs_descs.sink, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 1 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), }, .source = { .bLength = sizeof descriptors.hs_descs.source, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 2 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(512), .bInterval = 1, /* NAK every 1 uframe */ }, }, .ss_count = cpu_to_le32(5), .ss_descs = { .intf = { .bLength = sizeof descriptors.fs_descs.intf, .bDescriptorType = USB_DT_INTERFACE, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, .bInterfaceSubClass = 0xFF, .bInterfaceProtocol = 0xFF, .iInterface = 0, }, .sink = { .bLength = sizeof descriptors.hs_descs.sink, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 1 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), }, .sink_comp = { .bLength = USB_DT_SS_EP_COMP_SIZE, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 0, .bmAttributes = 0, .wBytesPerInterval = 0, }, .source = { .bLength = sizeof descriptors.hs_descs.source, .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 2 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, .wMaxPacketSize = cpu_to_le16(1024), .bInterval = 1, /* NAK every 1 uframe */ }, .source_comp = { .bLength = USB_DT_SS_EP_COMP_SIZE, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, .bMaxBurst = 0, .bmAttributes = 0, .wBytesPerInterval = 0, }, }, .os_count = cpu_to_le32(2), .os_compat = { .header = { .interface = 0, .dwLength = cpu_to_le32(sizeof descriptors.os_compat), .bcdVersion = cpu_to_le16(0x01), .wIndex = cpu_to_le16(0x0004), .bCount = 0x01, .Reserved= 0x00, }, .function = { .bFirstInterfaceNumber = 0x0, .Reserved1 = 0x01, .CompatibleID = "WINUSB\0\0", .SubCompatibleID = {0, 0, 0, 0, 0, 0, 0, 0}, .Reserved2 = {0, 0, 0, 0, 0, 0}, } }, .os_prop = { .header= { .interface = 0, .dwLength = cpu_to_le32(sizeof descriptors.os_prop), .bcdVersion = cpu_to_le16(0x01), .wIndex = cpu_to_le16(0x0005), .wCount = cpu_to_le16(0x0001), }, .desc = { .dwSize=cpu_to_le32(sizeof(descriptors.os_prop.desc) +sizeof(descriptors.os_prop.bPropertyName) +sizeof (descriptors.os_prop.wPropertyDataLength) +sizeof(descriptors.os_prop.bPropertyData)), .dwPropertyDataType = cpu_to_le32(0x00000001), .wPropertyNameLength = cpu_to_le16(20), }, .bPropertyName = "DeviceInterfaceGUID\0", .wPropertyDataLength = cpu_to_le32(39), .bPropertyData = "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\0", }, };
将BeagleBone连接到Windows10主机后,设备在设备管理器中显示为“其他设备”,而非“通用串行总线设备”,且无法与设备通信。已配置必要的描述符,但Windows似乎未接收到识别为WINUSB设备所需的信息,请问遗漏了什么配置?
解决方案
以下是几个关键遗漏点和修复步骤:
1. 缺少USB控制器绑定步骤
脚本最后未将USB控制器绑定到gadget,导致Windows无法完成设备枚举。需要添加:
# 先通过`ls /sys/class/udc/`查看可用的UDC节点,替换为你的设备对应名称 echo "musb-hdrc.0.auto" > UDC
这一步会激活gadget,让主机识别到完整的USB设备。
2. OS描述符配置细节错误
- 确保
os_desc目录存在,若不存在需提前创建:mkdir -p os_desc echo MSFT100 > os_desc/qw_sign必须是大写无空格,Windows对该签名的大小写敏感,小写会导致OS描述符不被识别。
3. WINUSB属性描述符长度计算错误
os_prop.desc.dwSize的计算逻辑有误,正确的长度应包含属性名称、数据的实际字节数(包括终止符),而非直接使用sizeof。修改为:
.dwSize = cpu_to_le32( sizeof(struct usb_os_desc_prop_header) + strlen("DeviceInterfaceGUID") + 1 + // 包含'\0' sizeof(descriptors.os_prop.wPropertyDataLength) + strlen("{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}") + 1 ),
错误的长度计算会导致Windows解析属性描述符失败,无法识别WINUSB设备。
4. 权限与进程运行问题
挂载functionfs后,/dev/ffs-usb0的默认权限可能无法让普通用户访问,导致ffs-test程序无法操作端点。添加权限配置:
sudo chmod 777 /dev/ffs-usb0
或者直接以root用户运行ffs-test二进制文件,确保程序能正常读写端点文件。
5. 冲突驱动检查
通过lsmod | grep usb_f_查看已加载的USB gadget驱动,确保只有usb_f_fs在运行,避免其他驱动干扰设备枚举。
内容的提问来源于stack exchange,提问作者Ken
相关产品推荐
相关产品推荐

