4

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):

  • Configuration 1, with the following interfaces:
    • RNDIS
    • CDC ACM 0
    • CDC ACM 1
  • Configuration 2, with the following interfaces:
    • CDC ECM
    • CDC ACM 0
    • CDC ACM 1

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?

Pavel Kirienko
  • 1,162
  • 1
  • 15
  • 31

1 Answers1

6

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
Pavel Kirienko
  • 1,162
  • 1
  • 15
  • 31
  • Hi there, I am really interested about CDC_ECM on WIN7 as well. Would you be able to paste you inf file ? please – Tom Mar 24 '17 at 19:15
  • Hi Tom, we ended up working only with Windows 10 and newer (although there are no newer versions out there yet). Windows starting from 10 got the automatic driver loading feature for all known USB classes (finally!), which removed the need to distribute `.inf` files as long as you stick to well known interfaces, such as RNDIS or CDC-ACM. I know that this answer won't really help you with Win 7. You should either consider upgrading to Win 10, or just Google some examples of how to write your own inf file, it's not overly hard. Hope this helps! – Pavel Kirienko Mar 24 '17 at 21:54