linuxusbembedded-linuxcdcrndis

Composite USB CDC Gadget doesn't work with Windows hosts


I have an embedded Linux 3.19 system with a USB device interface. The device needs to expose three USB interfaces to the host: a virtual network interface (RNDIS or CDC ECM) and two virtual serial ports (CDC ACM). The device needs to cooperate with modern Windows (7+) and Linux (3.16+) hosts.

Seeing as Windows doesn't natively support CDC ECM, we decided to implement two USB configurations (this is a popular approach):

The intention is to let Windows use the first configuration with RNDIS, which is natively supported (Windows always selects first USB configuration); and let non-Windows hosts use the second configuration with CDC ECM.

I put together a script (based on a similar script by David Lechner): http://pastebin.com/VtAusEmf. Relevant part of the script is provided below (please follow the link to see the full script, it's rather large):

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

The resulting Gadget configuration works fine with Linux hosts (second configuration gets selected, all three interfaces are available and working), but Windows hosts (tested with 8 and 10) only detect the RNDIS interface, ignoring the ACM interfaces. The RNDIS works well though.

If I disable the RNDIS interface, Windows hosts only detect the first ACM interface, ignoring the second one.

I suspect that Windows is incapable of handling composite USB devices properly. Is it so, or am I doing something wrong? If it is so, do I have to write my own .inf file, specifying which class drivers need to be loaded?


Solution

  • RTFM helped. The requirements to composite USB devices are described in these articles:

    Solution:

    echo "0xEF" > ${g}/bDeviceClass
    echo "0x02" > ${g}/bDeviceSubClass
    echo "0x01" > ${g}/bDeviceProtocol