Композитный USB CDC гаджет не работает с хостами Windows
У меня есть встроенная система Linux 3.19 с интерфейсом USB-устройства. Устройство должно предоставить хосту три интерфейса USB: виртуальный сетевой интерфейс (RNDIS или CDC ECM) и два виртуальных последовательных порта (CDC ACM). Устройство должно взаимодействовать с современными хостами Windows (7+) и Linux (3.16+).
Поскольку Windows изначально не поддерживает CDC ECM, мы решили реализовать две конфигурации USB (это популярный подход):
- Конфигурация 1 со следующими интерфейсами:
- RNDIS
- CDC ACM 0
- CDC ACM 1
- Конфигурация 2 со следующими интерфейсами:
- CDC ECM
- CDC ACM 0
- CDC ACM 1
Намерение состоит в том, чтобы позволить Windows использовать первую конфигурацию с RNDIS, которая изначально поддерживается (Windows всегда выбирает первую конфигурацию USB); и пусть не-Windows хосты используют вторую конфигурацию с CDC ECM.
Я собрал сценарий (на основе аналогичного сценария Дэвида Лехнера): http://pastebin.com/VtAusEmf. Соответствующая часть скрипта представлена ниже (пожалуйста, перейдите по ссылке, чтобы увидеть полный скрипт, он довольно большой):
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
Полученная конфигурация гаджета прекрасно работает с хостами Linux (выбрана вторая конфигурация, все три интерфейса доступны и работают), но хосты Windows (протестированные с 8 и 10) обнаруживают только интерфейс RNDIS, игнорируя интерфейсы ACM. RNDIS работает хорошо, хотя.
Если я отключаю интерфейс RNDIS, хосты Windows обнаруживают только первый интерфейс ACM, игнорируя второй.
Я подозреваю, что Windows не способна правильно обрабатывать композитные USB-устройства. Это так или я что-то не так делаю? Если это так, я должен написать свой собственный .inf
файл, определяющий, какие драйверы класса должны быть загружены?
1 ответ
RTFM помог. Требования к композитным USB-устройствам описаны в следующих статьях:
- https://msdn.microsoft.com/en-us/library/windows/hardware/ff537109(v=vs.85).aspx
- https://msdn.microsoft.com/en-us/library/windows/hardware/ff540054(v=vs.85).aspx
- https://msdn.microsoft.com/en-us/library/windows/hardware/ff538820(v=vs.85).aspx
Решение:
echo "0xEF" > ${g}/bDeviceClass
echo "0x02" > ${g}/bDeviceSubClass
echo "0x01" > ${g}/bDeviceProtocol