Composite USB CDC Gadget 不适用于 Windows 主机
Composite USB CDC Gadget doesn't work with Windows hosts
我有一个带 USB 设备接口的嵌入式 Linux 3.19 系统。设备需要向主机公开三个 USB 接口:一个虚拟网络接口(RNDIS 或 CDC ECM)和两个虚拟串行端口(CDC ACM)。该设备需要与现代 Windows (7+) 和 Linux (3.16+) 主机合作。
鉴于 Windows 本身不支持 CDC ECM,我们决定实施两种 USB 配置(这是一种流行的方法):
- 配置一,接口如下:
- RNDIS
- CDC ACM 0
- CDC ACM 1
- 配置二,接口如下:
- CDC ECM
- CDC ACM 0
- CDC ACM 1
目的是让Windows使用原生支持的RNDIS的第一个配置(Windows总是选择第一个USB配置);并让非 Windows 主机使用 CDC ECM 的第二个配置。
我整理了一个脚本(基于 David Lechner 的类似脚本):http://pastebin.com/VtAusEmf。下面提供了脚本的相关部分(请按照link查看完整脚本,它相当大):
mkdir -p ${g}
echo "${usb_ver}" > ${g}/bcdUSB
echo "${dev_class}" > ${g}/bDeviceClass
echo "${vid}" > ${g}/idVendor
echo "${pid}" > ${g}/idProduct
mkdir ${g}/strings/0x409
echo "${mfg}" > ${g}/strings/0x409/manufacturer
echo "${prod}" > ${g}/strings/0x409/product
echo "${serial}" > ${g}/strings/0x409/serialnumber
mkdir ${g}/configs/c.1
echo "${attr}" > ${g}/configs/c.1/bmAttributes
echo "${pwr}" > ${g}/configs/c.1/MaxPower
mkdir ${g}/configs/c.1/strings/0x409
echo "${cfg1}" > ${g}/configs/c.1/strings/0x409/configuration
echo "1" > ${g}/os_desc/use
echo "${ms_vendor_code}" > ${g}/os_desc/b_vendor_code
echo "${ms_qw_sign}" > ${g}/os_desc/qw_sign
mkdir ${g}/functions/rndis.usb0
echo "${dev_mac}" > ${g}/functions/rndis.usb0/dev_addr
echo "${host_mac}" > ${g}/functions/rndis.usb0/host_addr
echo "${ms_compat_id}" > ${g}/functions/rndis.usb0/os_desc/interface.rndis/compatible_id
echo "${ms_subcompat_id}" > ${g}/functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id
mkdir ${g}/configs/c.2
echo "${attr}" > ${g}/configs/c.2/bmAttributes
echo "${pwr}" > ${g}/configs/c.2/MaxPower
mkdir ${g}/configs/c.2/strings/0x409
echo "${cfg2}" > ${g}/configs/c.2/strings/0x409/configuration
mkdir ${g}/functions/ecm.usb0
echo "${dev_mac}" > ${g}/functions/ecm.usb0/dev_addr
echo "${host_mac}" > ${g}/functions/ecm.usb0/host_addr
mkdir ${g}/functions/acm.GS0
mkdir ${g}/functions/acm.GS1
ln -s ${g}/configs/c.1 ${g}/os_desc
ln -s ${g}/functions/rndis.usb0 ${g}/configs/c.1
ln -s ${g}/functions/acm.GS0 ${g}/configs/c.1
ln -s ${g}/functions/acm.GS1 ${g}/configs/c.1
ln -s ${g}/functions/ecm.usb0 ${g}/configs/c.2
ln -s ${g}/functions/acm.GS0 ${g}/configs/c.2
ln -s ${g}/functions/acm.GS1 ${g}/configs/c.2
echo "${device}" > ${g}/UDC
生成的 Gadget 配置在 Linux 主机上工作良好(选择了第二个配置,所有三个接口都可用且工作),但 Windows 主机(用 8 和 10 测试)仅检测RNDIS 接口,忽略 ACM 接口。不过 RNDIS 运行良好。
如果我禁用 RNDIS 接口,Windows 主机只检测第一个 ACM 接口,忽略第二个。
我怀疑 Windows 无法正确处理复合 USB 设备。是这样,还是我做错了什么?如果是这样,我是否必须编写自己的 .inf
文件,指定需要加载哪些 class 驱动程序?
RTFM 提供了帮助。这些文章中描述了对复合 USB 设备的要求:
- https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/enumeration-of-the-composite-parent-device
- https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-interface-association-descriptor
- https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/supported-usb-classes
解决方案:
echo "0xEF" > ${g}/bDeviceClass
echo "0x02" > ${g}/bDeviceSubClass
echo "0x01" > ${g}/bDeviceProtocol
我有一个带 USB 设备接口的嵌入式 Linux 3.19 系统。设备需要向主机公开三个 USB 接口:一个虚拟网络接口(RNDIS 或 CDC ECM)和两个虚拟串行端口(CDC ACM)。该设备需要与现代 Windows (7+) 和 Linux (3.16+) 主机合作。
鉴于 Windows 本身不支持 CDC ECM,我们决定实施两种 USB 配置(这是一种流行的方法):
- 配置一,接口如下:
- RNDIS
- CDC ACM 0
- CDC ACM 1
- 配置二,接口如下:
- CDC ECM
- CDC ACM 0
- CDC ACM 1
目的是让Windows使用原生支持的RNDIS的第一个配置(Windows总是选择第一个USB配置);并让非 Windows 主机使用 CDC ECM 的第二个配置。
我整理了一个脚本(基于 David Lechner 的类似脚本):http://pastebin.com/VtAusEmf。下面提供了脚本的相关部分(请按照link查看完整脚本,它相当大):
mkdir -p ${g}
echo "${usb_ver}" > ${g}/bcdUSB
echo "${dev_class}" > ${g}/bDeviceClass
echo "${vid}" > ${g}/idVendor
echo "${pid}" > ${g}/idProduct
mkdir ${g}/strings/0x409
echo "${mfg}" > ${g}/strings/0x409/manufacturer
echo "${prod}" > ${g}/strings/0x409/product
echo "${serial}" > ${g}/strings/0x409/serialnumber
mkdir ${g}/configs/c.1
echo "${attr}" > ${g}/configs/c.1/bmAttributes
echo "${pwr}" > ${g}/configs/c.1/MaxPower
mkdir ${g}/configs/c.1/strings/0x409
echo "${cfg1}" > ${g}/configs/c.1/strings/0x409/configuration
echo "1" > ${g}/os_desc/use
echo "${ms_vendor_code}" > ${g}/os_desc/b_vendor_code
echo "${ms_qw_sign}" > ${g}/os_desc/qw_sign
mkdir ${g}/functions/rndis.usb0
echo "${dev_mac}" > ${g}/functions/rndis.usb0/dev_addr
echo "${host_mac}" > ${g}/functions/rndis.usb0/host_addr
echo "${ms_compat_id}" > ${g}/functions/rndis.usb0/os_desc/interface.rndis/compatible_id
echo "${ms_subcompat_id}" > ${g}/functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id
mkdir ${g}/configs/c.2
echo "${attr}" > ${g}/configs/c.2/bmAttributes
echo "${pwr}" > ${g}/configs/c.2/MaxPower
mkdir ${g}/configs/c.2/strings/0x409
echo "${cfg2}" > ${g}/configs/c.2/strings/0x409/configuration
mkdir ${g}/functions/ecm.usb0
echo "${dev_mac}" > ${g}/functions/ecm.usb0/dev_addr
echo "${host_mac}" > ${g}/functions/ecm.usb0/host_addr
mkdir ${g}/functions/acm.GS0
mkdir ${g}/functions/acm.GS1
ln -s ${g}/configs/c.1 ${g}/os_desc
ln -s ${g}/functions/rndis.usb0 ${g}/configs/c.1
ln -s ${g}/functions/acm.GS0 ${g}/configs/c.1
ln -s ${g}/functions/acm.GS1 ${g}/configs/c.1
ln -s ${g}/functions/ecm.usb0 ${g}/configs/c.2
ln -s ${g}/functions/acm.GS0 ${g}/configs/c.2
ln -s ${g}/functions/acm.GS1 ${g}/configs/c.2
echo "${device}" > ${g}/UDC
生成的 Gadget 配置在 Linux 主机上工作良好(选择了第二个配置,所有三个接口都可用且工作),但 Windows 主机(用 8 和 10 测试)仅检测RNDIS 接口,忽略 ACM 接口。不过 RNDIS 运行良好。
如果我禁用 RNDIS 接口,Windows 主机只检测第一个 ACM 接口,忽略第二个。
我怀疑 Windows 无法正确处理复合 USB 设备。是这样,还是我做错了什么?如果是这样,我是否必须编写自己的 .inf
文件,指定需要加载哪些 class 驱动程序?
RTFM 提供了帮助。这些文章中描述了对复合 USB 设备的要求:
- https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/enumeration-of-the-composite-parent-device
- https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-interface-association-descriptor
- https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/supported-usb-classes
解决方案:
echo "0xEF" > ${g}/bDeviceClass
echo "0x02" > ${g}/bDeviceSubClass
echo "0x01" > ${g}/bDeviceProtocol