Как в Windows отправить control transfer устройству USB?

Тема в разделе "WASM.X64", создана пользователем flammmable, 20 апр 2023.

Метки:
  1. flammmable

    flammmable New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2023
    Сообщения:
    6
    У меня есть мост USB-UART XR21V1410. Согласно даташиту, он может отправлять/принимать (в том числе) символы UART в формате 9N1 - девять значащих бит, без бита чётности, с одним битом подтверждения. Данный формат символов применяется в шине MDB (Multi-Drop Bus) - но не суть.

    Для работы с символами в подобном формате мост следует переключить в так называемый "расширенный" режим - wide mode. Делается это отправкой команды (control transfer) XR_SET_REG, которую драйвер данного моста поддерживает наряду со стандартными для мостов USB-UART командами SET_LINE_CODING, GET_LINE_CODING и SET_CONTROL_LINE_STATE.

    WinAPI прячет работу с последними тремя командами "под капот". Для настройки у неё есть SetCommState(), для непосредственного обмена данными - запись и чтение из файла.

    Я погуглил и нашёл пример использования XR_SET_REG. Но оно, видимо, для Линукса. А мне хотелось бы сконфигурировать мой мост на чистом WinAPI. Я начал искать, как отправить control transfer устройству USB на WinAPI.

    Для этого я прочитал пример Майкрософта "How to send a USB control transfer". Но он исключительно про драйверы KMDF/UMDF. В моём же случае драйверы уже имеются. Затем я прочитал пример Майкрософта "Access a USB device by using WinUSB functions". Там есть такой код:
    Код (C):
    1. int _tmain(int argc, _TCHAR* argv[])
    2. {
    3.    GUID guidDeviceInterface = OSR_DEVICE_INTERFACE; //in the INF file
    4.    HANDLE hDeviceHandle = INVALID_HANDLE_VALUE;
    5.    WINUSB_INTERFACE_HANDLE hWinUSBHandle = INVALID_HANDLE_VALUE;
    6. //  ...ещё несколько переменных...
    7.    bResult = GetDeviceHandle(guidDeviceInterface, &hDeviceHandle);
    8.    bResult = GetWinUSBHandle(hDeviceHandle, &hWinUSBHandle);
    9. //  ...БАМ-БАМ-БАМ, проворачиваем кучу всего интересного по хэндлу hWinUSBHandle, например...
    10.    bResult = ReadFromBulkEndpoint(hWinUSBHandle, &PipeID.PipeInId, cbSize);
    11.    system("PAUSE");
    12. done:
    13.    CloseHandle(hDeviceHandle);
    14.    WinUsb_Free(hWinUSBHandle);
    15.    return 0;
    16. }
    Константа OSR_DEVICE_INTERFACE встречается в примере всего один раз, с эдакой самоочевидностью "ну вы знаете, этот OSR_DEVICE_INTERFACE - кто его не знает".

    И у меня возник вопрос, если я знаю VID/PID моего устройства и нужный мне эндпойнт, как мне выяснить OSR_DEVICE_INTERFACE? Возможно ли его выяснить через последовательность, вроде такой:
    Код (C):
    1. deviceInfoSet = SetupDiCreateDeviceInfoList(&GUID_DEVCLASS_USB, NULL);
    2. allDevices = SetupDiGetClassDevsExA(NULL, NULL, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES,
    3. deviceInfoSet, NULL, NULL);
    4. for(devIndex = 0; SetupDiGetDeviceInfo(allDevices, devIndex, &deviceInfo);devIndex++)
    5. {
    6.      SetupDiGetDeviceInstanceIdA(deviceInfoSet, &deviceInfo, devId, 1024, &devIdLen);
    7.      if(...условие, что в этой итерации просматривается именно нужное мне устройство...)
    8.      {
    9. //        ...получение OSR_DEVICE_INTERFACE ...
    10.      }
    11. }
     
  2. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    Как мне кажется, комментарий
    как бы намекает, что для конкретного девайса это может быть константа, которую можно подсмотреть в .inf файле, например.
     
  3. flammmable

    flammmable New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2023
    Сообщения:
    6
    Говорите без намёков, здесь все свои.

    При подключении устройства, в диспетчере устройств появляются два новых пункта. Одно в разделе "Контроллеры USB" - "Составное USB устройство", второе в разделе "Порты (COM и LPT)" - "Устройство с последовательным интерфейсом USB (COM28)". Я зашёл в свойства обоих устройств, на вкладку "Сведения". Там в выпадающем списке "Свойства" я выбрал пункт "ИД оборудования".

    Для COM28 значение этого пункта
    USB\VID_04E2&PID_1410&REV_0001&MI_00
    USB\VID_04E2&PID_1410&MI_00

    Для составного USB-устройства значение этого пункта
    USB\VID_04E2&PID_1410&REV_0001
    USB\VID_04E2&PID_1410

    В принципе, "PID_1410" похож на XR21V1410, а "VID_04E2" соответствует компании Exar (которая разработала этот мост, а затем продалась MaxLinear).

    Далее, на этой вкладке я меняю свойство на "Имя INF". Для COM28 это "usbser.inf", для USB-устройства это "usb.inf". Я открываю соответствующие файлы *.inf по пути "C:\Windows\INF" и... не нахожу там ничего похожего на *1410*. Соответственно, константу для guidDeviceInterface всё также не понятно где брать.

    Возвращаясь к началу поста, я бы предложил говорить без намёков. Если вы знаете, где и как найти константу - к чему это напускание тумана загадочности и величия? Если не знаете - тем более, к чему?
     
  4. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    1.955
    На сайте производителя можно скачать Serial_Test_USB_V1.2.0.0.exe, который содержит в себе вот такие две конструкции:
    Код (Text):
    1. .00406CDA push 0
    2. .00406CDC lea ecx,dword ptr ss:[ebp-4]
    3. .00406CDF push ecx
    4. .00406CE0 push 0
    5. .00406CE2 push 0
    6. .00406CE4 push 0
    7. .00406CE6 push 0
    8. .00406CE8 push 22205C
    9. .00406CED push eax
    10. .00406CEE call dword ptr ds:[<&DeviceIoControl>]
    11. .00406CF4 mov ecx,esi
    12. .00406CF6 test eax,eax
    13. .00406CF8 jne serial_test_usb_v1.2.0.0.406D10
    14. .00406CFA push 10
    15. .00406CFC push serial_test_usb_v1.2.0.0.661F18    ;"Error"
    16. .00406D01 push serial_test_usb_v1.2.0.0.6621BC    ;"Error calling IOCTL_XRUSBPORT_ENABLE_WIDE_MODE!"
    17.  
    18. .00406C69 push 0
    19. .00406C6B lea ecx,dword ptr ss:[ebp-4]
    20. .00406C6E push ecx
    21. .00406C6F push 0
    22. .00406C71 push 0
    23. .00406C73 push 0
    24. .00406C75 push 0
    25. .00406C77 push 222060
    26. .00406C7C push eax
    27. .00406C7D call dword ptr ds:[<&DeviceIoControl>]
    28. .00406C83 mov ecx,esi
    29. .00406C85 test eax,eax
    30. .00406C87 jne serial_test_usb_v1.2.0.0.406C9F
    31. .00406C89 push 10
    32. .00406C8B push serial_test_usb_v1.2.0.0.661F18   ;"Error"
    33. .00406C90 push serial_test_usb_v1.2.0.0.662188   ;"Error calling IOCTL_XRUSBPORT_DISABLE_WIDE_MODE!"
    Очевидно wide mode устанавливается DeviceIoControl(,0x22205C,,,,,,) и отключается DeviceIoControl(,0x222060,,,,,,). Вот как бы и всё. Наверняка там где-то можно нарыть сдк и там это тоже будет описано, но лень искать.
     
    sn0w нравится это.
  5. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    441
    Когда то давным давно я работал напрямую с особым протоколом принтеров подключаемых в COM-порт. Особые принтеры со своим языком команд который надо засылать прямо установив соединение.
    У меня был ступор когда эти принтеры перешли на USB-протокол, т.к. никакого виртуального COM-порта драйверами в системе не проявлялось, а драйвера просто имитировали обычный принтер Windows со всеми вытекающими: любая печать превращалась в пересылку битмапов и безбожно тормозила и создавала кровавый геморрой с полями печати там где достаточно было закинуть несколько десятков байт нативных команд (по сути винда просто всё время слала нативную команду "отобразить битмап". Меня это не устраивало и я начал усиленно копать как вернуть COM-порт взад.
    И потом я обнаружил интересное - даже если не установлены драйвера, то при подключении к такого принтера к компу в системе USB проскакивали сообщения о появлении в системе точки подключения к serial-девайсу: https://gamedev.ru/flame/forum/?id=51653&page=2
    При этом из гуида который возвращается можно сформировать истинное имя порта девайса которое имеет вид типа \\.\GUID - само перечисление возвращает вместо точки в этой сентенции знак вопроса или наоборот.
    Строку с этим делом можно использовать в обычном OpenFile чтобы открыть порт принтера напрямую как будто бы это COM-порт и спокойно работать дальше даже без установки драйверов. Просто воткнул девайс в новый комп, увидел в программе какой гуид при этом появляется в системе USB и используешь его после небольшой замены символов как имя порта.
    Так вот, подозреваю, что речь именно об этом гуиде идёт тут.
     
  6. f13nd

    f13nd Well-Known Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    1.955
    Здесь проблема скорее в этом:
    изображение_2023-04-21_034821939.png
    Есть шнурок с некоторым кастомным функционалом, но документации по нему кроме брошюрок с картинками для дебилов нету. Наверное так разрабы намекают, что покупкой шнурка ты не отделаешься.
     
  7. ormoulu

    ormoulu Well-Known Member

    Публикаций:
    0
    Регистрация:
    24 янв 2011
    Сообщения:
    1.208
    Не знаю, могу только предположить.
    Вот пара примеров кода от азиатских товарищей:

    https://www.twblogs.net/a/5b898b2b2b71775d1ce25806
    https://q.cnblogs.com/q/51027/

    Загуглив значения (лет ми ду ит фор ю) видим, что эти гуиды соответствуют Bus Type Guid, который как раз можно найти в диспетчере задач, вкладка Details.
     
  8. FoxB

    FoxB Member

    Публикаций:
    0
    Регистрация:
    10 июл 2003
    Сообщения:
    109
    в нетах встречаютс разные упоминания, например:
    static const GUID OSR_DEVICE_INTERFACE[] = { 0xD696BFEB, 0x1734, 0x417d, { 0x8A, 0x04, 0x86,0xD0,0x10,0x71,0xC5,0x12 } };

    может это поможет
    https://github.com/MicrosoftDocs/wi...pr/usbcon/automatic-installation-of-winusb.md
    --- Сообщение объединено, 21 апр 2023 ---
    https://github.com/MicrosoftDocs/wi...#writing-a-custom-inf-for-winusb-installation
    --- Сообщение объединено, 21 апр 2023 ---
    "в студию"
     
    Последнее редактирование: 21 апр 2023
  9. flammmable

    flammmable New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2023
    Сообщения:
    6
    Огромное спасибо! Всё получилось!!