Скрещиваем LRNDIS проект с HAL Cube MX

Это не обязательно , но как-то привычнее с HAL из Cube MX работать. Сделаем проект в Cube Mx под STM32F205VG .

Поскольку нам надо создать RNDIS , а списке выбора вариантов его нет, то просто выберем любой другой , например Communication Device Class VCOM. Далее мы его переделаем в RNDIS.

В результате получаем стандартную инициализацию USBD устройства.

Схема инициализации стандартная для всех USBD :

MX_USB_DEVICE_Init  [usb_device.c]
   USBD_Init(&hUsbDeviceFS, &FS_Desc, DEVICE_FS)  [usbd_core.c]
   // тут инициализация клоков, частот периферии USB
   USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC)
   // тут мы переделаем указатель с USBD_CDC на наш калсс
   USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS)
   // тоже переделаем
   USBD_Start(&hUsbDeviceFS)

Наша задача на первом этапе - подсунуть инициализацию RNDIS варианта и увидеть, что такое устройство появилось у хоста.

USBD_Init

Что в USBD_Init :

первый параметр USBD_HandleTypeDef

typedef struct _USBD_HandleTypeDef
{
  uint8_t                 id;
  uint32_t                dev_config;
  uint32_t                dev_default_config;
  uint32_t                dev_config_status; 
  USBD_SpeedTypeDef       dev_speed; 
  USBD_EndpointTypeDef    ep_in[15];
  USBD_EndpointTypeDef    ep_out[15];  
  uint32_t                ep0_state;  
  uint32_t                ep0_data_len;     
  uint8_t                 dev_state;
  uint8_t                 dev_old_state;
  uint8_t                 dev_address;
  uint8_t                 dev_connection_status;  
  uint8_t                 dev_test_mode;
  uint32_t                dev_remote_wakeup;

  USBD_SetupReqTypedef    request;
  USBD_DescriptorsTypeDef *pDesc; 
  // здесь указатели на функции , код которых надо заменить
  USBD_ClassTypeDef       *pClass;     
   // здесь указатель на класс , его надо заменить
  void                    *pClassData;  
  void                    *pUserData;    
  void                    *pData;    
} USBD_HandleTypeDef;

USBD_DescriptorsTypeDef - здесь указатели на функции , которые хост будет запрашивать сразу после подключения устройства :

typedef struct
{
  uint8_t  *(*GetDeviceDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);  
  uint8_t  *(*GetLangIDStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); 
  uint8_t  *(*GetManufacturerStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);  
  uint8_t  *(*GetProductStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);  
  uint8_t  *(*GetSerialStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);  
  uint8_t  *(*GetConfigurationStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length);  
  uint8_t  *(*GetInterfaceStrDescriptor)( USBD_SpeedTypeDef speed , uint16_t *length); 
} USBD_DescriptorsTypeDef;

Что мне "нравится" определения структур , названия функций т .д. : все отличатся ( в наших двух проектах ).

Но в общем выходим на описание содержания нашего главного дескриптора USBD_FS_DeviceDesc ( исх. USBD_DeviceDesc) и видим отличия:
bDeviceClass разные, bDeviceSubClass тоже разные. [usbd_desr.c]

Заменяем в нашем VCOM выдачу дескриптора на RNDIS .

USBD_RegisterClass

Определение _Device_cb отличаются
USBD_ClassTypeDef _Device_cb

Заменяем регистрацию класса устройства на код из примера LRNDIS.

USBD_RegisterClass(&hUsbDeviceFS, &USBD_CDC)

hUsbDeviceFS это структура USBD_HandleTypeDef ;


USBD_CDC_RegisterInterface

.....

USBD_Start

....

И вот только теперь подключаем USB к ПК.

Ловим первое прерывание по USB :

OTG_FS_IRQHandler [stm32f2xx_it.c]
    HAL_PCD_IRQHandler [stm32f2xx_hal_pcd.c]
          HAL_PCD_SetupStageCallback [usbd_conf.c]
                 USBD_LL_SetupStage [usbd_core.c]
                        USBD_StdDevReq [usbd_ctlrec.c]
                        USBD_GetDescriptor [usbd_ctlrec.c]
                                          pdev->pDesc->GetDeviceDescriptor

Логический анализатор показывает, что по USB ответ прошел обратно хосту: но что-то хосту не нравится ...три раза хост пытается чиатает дескриптор.
( для информации : а вот USBLyzer не показывает , что данные на запрос дескриптора контроллер передал. )

0.689731750,SETUP,0x00,0x00,,,0x02
0.689735020,DATA0,,,,0x80 0x06 0x00 0x01 0x00 0x00 0x40 0x00,0x94DD
0.689743590,ACK,,,,,
 ......
0.690117130,IN,0x00,0x00,,,0x02
0.690120410,DATA1,,,,0x12 0x01 0x00 0x02 0xE0 0x00 0x00 0x28 
    0x44 0x4E 0x53 0x49 0xFF 0xFF 0x01 0x02 0x03 0x01,0x2F5A
0.690135850,ACK,,,,,

Берез чисто VCOM смотрим лог - вроде все похоже.

И находим вдруг в исходниках банальную ошибку : макс. длина end-point у нас 0x28 (40), надо было 0x40 (64) !

Далее процесс заметно полет дальше.

Как промежуточных результат : в системе хоста (win 10) появился VCOM как ни странно... Конечно ведь мы не меняли конфигурации и интерфейсы, а только подменили основной дескриптор.

Дескриптор конфигурации

И тут мы плавно подходим к изменению содержания дескриптора конфигурации USBD_CDC_CfgHSDesc | usbd_cdc_CfgDesc .

Это уже в файле конкретного класса описывается [usbd_cdc.c] или [usbd_rndis_core.c] соответственно.

Дескриптор конфигурации у нас отобрал три часа ремени, пока мы поняли , что размер поле 2 и 3 надо точно установить размеру всего дескриптора в байтах .

Теперь уже наше устройство в системе определилось как Remote NDIS based Internet Sharing Device #5

фотка 1

Далее на запросы остальных дескрипторов ответ происходит нормально.


Переходим к приему первой команды на End Point 0 (это управляющий энд пойнт).

Вот эта ветка вызовов :

OTG_FS_IRQHandler [stm32f2xx_it.c]
    HAL_PCD_IRQHandler [stm32f2xx_hal_pcd.c]
         HAL_PCD_DataOutStageCallback [usbd_conf.c]
               USBD_LL_DataOutStage [usbd_core.c]
                        USBD_CDC_EP0_RxReady [usbd_cdc.c]
                               CDC_Control_FS [usbd_cdc_if.c]

И только тут мы начинаем понимать насколько большой объем кода еще надо перелопатить. Так ака тут мы подходим к управляющим запросам уже к конткретному классу устройств (RNDIS).

На сайте usb.org наше устройство это wireless adapter 0xE0(Base Class) 0x01(SubClass) 0x03 (Protocol). И у него есть свой набор команд. 0x03 это Protocol Remote NDIS.

OTG_FS_IRQHandler [stm32f2xx_it.c]
HAL_PCD_IRQHandler [stm32f2xx_hal_pcd.c]
HAL_PCD_SetupStageCallback [usbd_conf.c]
USBD_LL_SetupStage [usbd_core.c]
USBD_StdDevReq [usbd_ctlrec.c]
USBD_GetDescriptor [usbd_ctlrec.c]
pdev->pDesc->GetDeviceDescriptor
HAL_PCD_DataInStageCallback [usbd_conf.c]
USBD_LL_DataInStage [usbd_core.c]
pdev->pClass->DataIn(pdev, epnum);
USBD_CDC_DataIn [usbd_cdc.c]

OTG_FS_IRQHandler [stm32f2xx_it.c]
HAL_PCD_IRQHandler [stm32f2xx_hal_pcd.c]
HAL_PCD_DataOutStageCallback
USBD_LL_DataOutStage
USBD_CDC_EP0_RxReady
CDC_Control_FS [usbd_cdc_if.c]