2021-09-29 usb枚举和cdc的传输

stm32f4 USB项目开发详解 - 小龙1356 - 博客园 (cnblogs.com)

1、一个设备可以有多个配置,不同的配置对应不同的功能

    比如,一个USB接口的CDROM,作为一个设备,

    它具有两种功能,1读取光盘 和  2播放CD,所以有2Configuration描述符

2、一个功能的实现要涉及许多接口,

    比如当CD播放机使用时,需要音频接口,同时还需要控制CD机的接口。 

3、一个接口又有许多端点组成,一般真正通信都是针对端点进行的,比如用端点0来进行控制枚举传输

    stm32  支持8个双向端点,16个单向端点,每个端点只能时一个方向(OUT / IN),除了端点0

OTG举例:当OTG插到电脑上时, OTG的角色就是连接电脑的device,也就是Slave;当USB device 插到OTG上的时候,,OTG的角色就是Host。

/********************usb设备描述符************************/

typedef volatile struct

{

    UINT8               *pDeviceDescriptor;

    UINT8               deviceDescriptorLength;

    UINT8               *pConfigDescriptor;

#ifdef CRANE_MCU_DONGLE

    UINT16               configDescriptorLength;

#else

    UINT8               configDescriptorLength;

#endif

         UINT8                                     *pQualifDescriptor;

         UINT8                                     qualifDescriptorLength;

         UINT8                                     *pOtherSpeedDescriptor;

         UINT8                                     otherSpeedDescriptorLength;

    UINT8               *pStringDescriptor[USB_DEVICE_TOTAL_STRINGS];

    UINT8               stringDescriptorTotal;

}USBDevice_DescriptorsS;

/**********************usb的功能描述符*******************************/

typedef volatile struct

{

    USBDevice_StatusE                                               status;

    USBDevice_EP0DataS                      ep0;

    USBDeviceStatusNotifyFn                 statusNotifyFn;

    USBDeviceVendorClassRequestNotifyFn     vendorClassRequestNotifyFn;

    USBDeviceEndpointZeroNotifyFn           endpointZeroNotifyFn;

}USBDevice_DatabaseS;

/***********************usb的端点描述符******************************/

typedef volatile struct

{

    BOOL                                    endpointOpen;

    BOOL                                    endpointBusy;

    UDC_EndpointE                           udcEndpoint;

    //YG - currently not in use: USBDevice_TransferStateE                transferState;//YG abortTransfer - can be used instead of Busy !!!;

    USBDeviceTransactionCompletedNotifyFn   transactionCompletedNotifyFn;

/* USB2.0 Additions Begin */

   UINT8*                                   pRxBuffer;                // points to rx buffer    - relevent for rx endpoint only

   UINT32                                   pRxBuffSize;              // rx buffer size         - relevent for rx endpoint only

   BOOL                                     zlp;       // indicates wether ZLP is needed when tansaction size = max packet size

/* USB2.0 Additions End */

}USBDevice_EndpointDataS;

Usb初始化过程:

Phase1Inits()

         USBDevicePhase1Init();

                   USB2DevicePhase1Init();   //初始化各功能

                            USB2DeviceDatabaseReset(); //描述符的初始化

"usb_driver.nvm"

Usb_DriverS usbDrvCfg = {USB_GENERIC_MOD_ECM_DRIVER, MASS_STORAGE_DISABLE, USB_AUTO_INSTALL_DISABLE, USB_OS_DETECT_DISABLE};

Phase2Inits()

usb_device_init()

             1.USBDevicePhase2Init(); //

(USB2DevicePhase2Init())//初始化usb的内存,中断处理,硬件初始化,_usb_device_register_service注册各种service,

            InitUSBMemoryPool() //初始化usb的内存

            _usb_device_register_service()//注册各种service

                     error = _usb_device_register_service(_usbDeviceHandle, MV_USB_SERVICE_BUS_RESET, USB2DeviceEventNotify);

                     USB2DeviceStartEp0(_usbDeviceHandle);

            USB2DeviceHWInit(); // usb时钟设置

                            _usb_device_init()://发送描述符(dtd)的初始化,usb硬件的初始化

                                     _usb_dci_vusb20_init()//初始化usb的设备结构体,usb设备控制器

                                               _usb_dci_vusb20_chip_initialize()//寄存器初始化

                   2.mvUsbModemInitialize(); // AT 、CDC等的端点处理注册在这里

                            mvUsbModem2RxHISR()//注册中断

                                     quec_uart_read_fifo_to_rb(QL_USB_CDC_PORT, RxPtr, txLength);

                                     quec_uart_send_msg(QL_USB_CDC_PORT);

                   3.USB2MgrUpdateDescriptor(pUsbDesInfo->ReConfigDesc, pUsbDesInfo->UsbMode);  //usb描述符更新

typedef enum //描述符类型

{

/**标准描述符**/

    USB_DESCRIPTOR_TYPE_DEVICE              = 1,               //设备描述符

    USB_DESCRIPTOR_TYPE_CONFIGURATION       = 2,   //配置描述符

    USB_DESCRIPTOR_TYPE_STRING              = 3,               //字符描述符

    USB_DESCRIPTOR_TYPE_INTERFACE           = 4,    //接口描述符

USB_DESCRIPTOR_TYPE_ENDPOINT            = 5,       //端点描述符

/**类描述符**/

    USB_DESCRIPTOR_TYPE_QUALIFIER           = 6,       /* Starting from here - USB2.0 Addition */ 设备限定描述符

    USB_DESCRIPTOR_TYPE_SPEED               = 7,               //其他速率配置描述符

    USB_DESCRIPTOR_TYPE_POWER               = 8,             //接口电源描述符

USB_DESCRIPTOR_TYPE_OTG                 = 9,                  //一般拷贝描述符

USB_DESCRIPTOR_TYPE_audio_interface =0x24       //音频类描述符

}USB_DescriptorTypesE;

Cdc的发送过程

void  mvUsbModem3SendData(UINT8 *bufPtr, UINT32 length)

txStatus = USBDeviceEndpointTransmit((USBDevice_EndpointE)TxEp,

                                                                                              (UINT8 *)bufPtr,

                                                                                              length,

                                                                                              TRUE);

                   error = _usb_device_send_data (_usbDeviceHandle, endpoint, pTxBuffer, txLength);

                            error = _usb_dci_vusb20_add_dTD(handle, xd_ptr);    //把dtd填充到

/*******运行端点********/                         

dev_ptr->REGISTERS.OPERATIONAL_DEVICE_REGISTERS.ENDPTPRIME = USB_32BIT_LE(bit_pos);   //运行端点

触发中断,回调对应service

Cdc的接收过程

1.判断端点完成

/***********注册中断**********/

                   usbStatus = USBDeviceEndpointOpen((USBDevice_EndpointE)QUEC_USB_CDC_RX_ENDPOINT,

                                     USB_DEVICE_USAGE_INTERRUPT,

                                     0,

                                     (UINT8 *)NULL,

                                     0,

                                     mvUsbModem2RxLISR);

void mvUsbModem2RxLISR(USBDevice_EndpointE ep ,UINT8 *data ,UINT32 Len ,BOOL end)

{

         {

                   osStatus = OS_Activate_HISR(&Modem2RxHISR);

         }

}

OS_Create_HISR(&Modem2RxHISR, "Mdm2RxH", mvUsbModem2RxHISR, HISR_PRIORITY_2);

void mvUsbModem2RxHISR(void)

         if(!IsMiniSystem())

                   quec_uart_read_fifo_to_rb(QL_USB_CDC_PORT, RxPtr, txLength);

                   quec_uart_send_msg(QL_USB_CDC_PORT);

/*各种中断和服务处理*/

void _usb_dci_vusb20_isr(_usb_device_handle handle)

         _usb_dci_vusb20_process_tr_complete((pointer)usb_dev_ptr);

                  _usb_device_call_service(handle, ep_num, FALSE, direction, buff_start_address, actual_transfer_length, errors);

                            service_ptr->SERVICE(handle, type, setup, direction, buffer_ptr, length, errors);  //SERVICE的服务进行发送

//USB2DeviceEndpointOpen也是调用到_usb_device_register_service 注册各端点的回调SERVICE

//SERVICE由如下_usb_device_register_service填充的函数:USB2DeviceTransactionCompleted

USB2DeviceTransactionCompleted函数里面调用了transactionCompletedNotifyFn,

由如下函数USB2DeviceEndpointOpen进行的填充;service_ptr->SERVICE调用到的函数USB2DeviceTransactionCompleted实际为transactionCompletedNotifyFn的处理

USBCDevice_ReturnCodeE USB2DeviceEndpointOpen(USBDevice_EndpointE                       endpoint,

                                            USBDevice_UsageTypeE                      usageType,

                                            UINT8                                     dmaChannel,

                                            UINT8                                     *pBuffer,

                                            UINT16                                    bufferLength,

                                            USBDeviceTransactionCompletedNotifyFn     transactionCompletedNotifyFn)

{

    /* convert USB endpoint into UDC endpoint */

    _usbDeviceEndpoint[endpoint].udcEndpoint = USBDeviceConvertUSB2UDCEndpoint(endpoint);

    error = _usb_device_register_service(_usbDeviceHandle, udcEndpoint, USB2DeviceTransactionCompleted);//service的填充

  

    error = _usb_device_init_endpoint(_usbDeviceHandle,

                                udcEndpoint,

                                udcDefaultEndpointCfg[udcEndpoint].usbMaxPacketSize,

                                udcDefaultEndpointCfg[udcEndpoint].usbEndpointDir,

                                udcDefaultEndpointCfg[udcEndpoint].usbEndpointType,

                                MV_USB_DEVICE_DONT_ZERO_TERMINATE);

        

    if ( pBuffer != NULL )

    {

        error = _usb_device_recv_data ( _usbDeviceHandle, udcEndpoint,  pBuffer, bufferLength);

       

            _usbDeviceEndpoint[endpoint].pRxBuffer    = pBuffer;

            _usbDeviceEndpoint[endpoint].pRxBuffSize  = bufferLength;

    }

    _usbDeviceEndpoint[endpoint].endpointOpen                   = TRUE;

    _usbDeviceEndpoint[endpoint].transactionCompletedNotifyFn   = transactionCompletedNotifyFn;

    _usbDeviceEndpoint[endpoint].zlp = ( (usageType & USB_DEVICE_NEED_ZLP) == USB_DEVICE_NEED_ZLP ? TRUE : FALSE);

} /* End of < USB2DeviceEndpointOpen > */

uint_8 _usb_device_register_service(_usb_device_handle         handle,uint_8                     type, void(_CODE_PTR_ service)(pointer, uint_8, boolean, uint_8, uint_8_ptr, uint_32, uint_8))

{

         service_ptr->SERVICE = service;

}

static void USB2DeviceTransactionCompleted (void* handle, uint_8  endpoint, boolean  setup, uint_8 direction, uint_8* buffer, uint_32 length, uint_8  error)

{

         //运行

    _usbDeviceEndpoint[endpoint].transactionCompletedNotifyFn( (USBDevice_EndpointE)endpoint, buffer, length, TRUE);     // YSS - RETURN HERE, CHECK/CHANGE REGARDING LAST PARAMETER end_of_transmit

    _usbDeviceEndpoint[endpoint].endpointBusy = FALSE;

}

  • Usb接入执行过程:

  1. EHCI_STS_SUSPEND  0x100

清除usb的发送

  1. EHCI_STS_RESET  0x40

地址为0、清除setup的端点状态、清除端点完成状态、清除端点的buffer内容、卸载端点、

  _usb_device_register_service(_usbDeviceHandle, MV_USB_SERVICE_BUS_RESET, USB2DeviceEventNotify);

_usbDeviceDescriptors

_usbDeviceDatabase  /* Endpoint 0 */

_usbDeviceEndpoint

清除usb端点的发送

         停止所有的端点  USB2DeviceStopEps

         初始化端点0 USB2DeviceStartEp0

                     _usb_device_init_endpoint(handle, 0, 64, MV_USB_SEND,  MV_USB_CONTROL_ENDPOINT, 0);

           

  1. EHCI_STS_PORT_CHANGE  0x4

使能端点

Resume

  1. EHCI_STS_INT   0x1

调用数据的收发

描述符:Quectel_AT_DIAG_ECM_UpdateDescriptor

◆ 用户将一个USB设备插入USB端口,主机为端口供电,设备此时处于上电状态。
◆ 主机检测设备。
◆ 集线器使用中断通道将事件报告给主机。
◆ 主机发送Get_Port_Status(读端口状态)请求,以获取更多的设备信息。
◆ 集线器检测设备是低速运行还是高速运行,并将此信息送给主机,这是对Get_Port_Status请求的响应。
◆ 主机发送Set_Port_Feature(写端口状态)请求给集线器,要求它复位端口。
◆ 集线器对设备复位。
◆ 主机使用Chirp K信号来了解全速设备是否支持高速运行。
◆ 主机发送另一个Get_Port_Status请求,确定设备是否已经从复位状态退出。
◆ 设备此时处于缺省状态,且已准备好在零端点通过缺省通道响应主机控制传输。缺省地址为00h,设备能从总线获取高达100mA的电流。


◆ 主机发送Get_Descriptor(读设备描述符)报文,以便确定最大数据包大小。设备描述符的八个字节是bMaxPacketSize。

80 06 00 01 0000 40 00          获取最大64的数据

12 01 00 02 ef 02 01 40 7c 2c 01 60 18 03 01 02 03 01   设备描述符(端点0最大数据)

12 长度

01 设备描述符类型

00 02     usb版本2.0

ef       设备类型

02     子类掩码

01     协议码

40     端点0最大数据

7c 2c    VID

01 60    PID

18 03    设备发行号

01          厂商信息的字符串描述符的索引值

02          产品信息的字串描述符的索引值

03          设备序列号信息的字串描述符的索引值

01                 配置描述符数目


◆ 通过发送Set_Address(写地址)请求,主机分配地址,设备此时处于地址状态。

00 05 2b 00 00 00 00 00          设备地址:002b
◆ 主机发送Get_Descriptor报文,以获取更多的设备信息。主机通过发送描述符响应设备请求,随后发送全部的次级描述符。

80 06 00 01 00 00 12 00         获取18字节设备描述符

12 01 00 02 ef 02 01 40 7c 2c 01 60 18 03 01 02 03 01


◆获取配置描述符(275个数据)

80 06 00 02 00 00 13 01

发送的包含配置、接口、端点描述符

09 02 13 01 07 01 00 c0 fa   Configuration Descriptor 配置描述符

09    此描述符的长度

02     类型

13 01  数据总长。包括配置,接口,端点和设备类及厂商定义的描述符

07     接口个数

01     SetConfiguration()设定此配置

00     字串描述表索引

c0      GetStatus(DEVICE) 请求得到,需要从总线取的电量

fa   总线电源耗费量。以 2mA 为一个单位

接口1

08 0b 00 02 02 06 00 05         Interface0,1 Descriptor,ECM-接口关联描述符

长度、类型、关联的接口号、接口数量、类码、子类码、协议码、字符串描述符索引

09 04 00 00 01 02 06 00 05    Standard Interface Descriptor 接口描述符

09 长度

04 接口类型

00 接口号

00 可选配置的索引值

01 端点数量

02 接口所属的类值,bInterfaceClass:CDC控制类

06 子类码,视bInterfaceClass域而定

00 协议码,指出了设备类说明中所定义的协议

05 描述此接口的字串描述表的索引值

05 24 00 10 01                       CDC Header functional descriptor 音频类描述符

0d 24 0f 0e 00 00 00 00 08 06 01 00 00    ECM functional descriptor 音频类描述符

05 24 06 00 01                       CDC Header functional descriptor 音频类描述符

07 05 87 03 40 00 10                       Standard Endpoint Descriptor 端点描述符

07 长度

05 端点类型

87 输入,端点号

03 位图(中断传输)

40 00  最大的包长度

10 周期间隙(ms),同步的时间域必须为0

接口2  Standard Interface Descriptor

09 04 01 00 00 0a 00 00 05     Standard Interface Descriptor(0a:cdc数据类)

09 04 01 01 02 0a 00 00 00     Standard Interface Descriptor

07 05 83 02 00 02 00                       Standard Endpoint Descriptor

07 05 0c 02 00 02 00                       Standard Endpoint Descriptor

接口3  Interface2 Descriptor,,DIAG

09 04 02 00 02 ff 00 00 08      Interface2 Descriptor,,DIAG(厂家自定义)

07 05 82 02 00 02 00                       Standard Endpoint Descriptor

07 05 0b 02 00 02 00                       Standard Endpoint Descriptor

接口4  Interface3 Descriptor,,AT

09 04 03 00 03 ff 00 00 0b      Interface3 Descriptor,,AT(厂家自定义)

05 24 00 10 01                       Header functional descriptor

05 24 01 00 00                       Call Management Functional Descriptor

04 24 02 02                            Abstract Control Management Functional Descriptor

05 24 06 00 00                       Union Functional Descriptor

07 05 89 03 40 00 10                       Standard Endpoint Descriptor ctrl

07 05 86 02 00 02 00                       Standard Endpoint Descriptor tx

07 05 0f 02 00 02 00                        Standard Endpoint Descriptor rx

接口5  Interface5 Descriptor,, CDC UART

09 04 04 00 03 ff 00 00 0b      Interface5 Descriptor,, CDC UART(厂家自定义)

05 24 00 10 01                       Header functional descriptor

05 24 01 00 00                       Call Management Functional Descriptor

04 24 02 02                            Abstract Control Management Functional Descriptor

05 24 06 00 00                       Union Functional Descriptor

07 05 88 03 40 00 10                       modem Endpoint Descriptor ctrl

07 05 81 02 00 02 00                       modem Endpoint Descriptor tx

07 05 0a 02 00 02 00                       modem Endpoint Descriptor rx

接口6  cdc新增

08 0b 05 02 02 02 01 08         INTERFACE ASSOCIATION DESCRIPTOR

09 04 05 00 01 02 02 01 08    Standard  Interface Descriptor(02:cdc控制类;08:字符索引)

05 24 00 10 01                       Header functional descriptor

05 24 01 00 06                       Call Management Functional Descriptor

04 24 02 02                            Abstract Control Management Functional Descriptor

05 24 06 05 06                       Union Functional Descriptor

07 05 85 03 40 00 10                       CDC Endpoint Descriptor ctrl

接口7  cdc新增

09 04 06 00 02 0a 00 00 0b    Standard  Interface Descriptor  (0a:cdc数据类)

07 05 84 02 00 02 00                       CDC Endpoint Descriptor tx

07 05 0d 02 00 02 00                       CDC Endpoint Descriptor rx

◆获取字符描述符

80 06 00 03 00 00 ff 00

04 03 09 04   

长度、类型(字符串描述符)、英语符(2字节)

◆设置配置

00 09 0001 0000 0000

◆设置接口

01 0b 0000 0001 0000

              

◆获取字符描述符

80 06 0305 0409 0036

36 03 4d 00 6f 00 62 00 69 00 6c 00 65 00 20 00 45 00 43 00 4d 00 20 00 4e 00 65 00 74 00 77 00 6f 00 72 00 6b 00 20 00 41 00 64 00 61 00 70 00 74 00 65 00 72 00

static __align(8) UINT8 strMobileECM[] =

{

    0x36, 0x03, 0x4D, 0x00, 0x6F, 0x00, 0x62, 0x00,\

    0x69, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x20, 0x00,\

    0x45, 0x00, 0x43, 0x00, 0x4D, 0x00, 0x20, 0x00,\

    0x4E, 0x00, 0x65, 0x00, 0x74, 0x00, 0x77, 0x00,\

    0x6F, 0x00, 0x72, 0x00, 0x6B, 0x00, 0x20, 0x00,\

    0x41, 0x00, 0x64, 0x00, 0x61, 0x00, 0x70, 0x00,\

    0x74, 0x00, 0x65, 0x00, 0x72, 0x00

};

80 06 0301 0409 00ff

10 03 41 00 6e 00 64 00 72 00 6f 00 69 00 64 00

80 06 0308 0409 002c

2c 03 4d 00 6f 00 62 00 69 00 6c 00 65 00 20 00 44 00 69 00 61 00 67 00 20 00 49 00 6e 00 74 00 65 00 72 00 66 00 61 00 63 00 65 00

80 06 0302 0409 00ff

10 03 41 00 6e 00 64 00 72 00 6f 00 69 00 64 00

80 06 030b 0409 0028

28 03 4d 00 6f 00 62 00 69 00 6c 00 65 00 20 00 41 00 54 00 20 00 49 00 6e 00 74 00 65 00 72 00 66 00 61 00 63 00 65 00

◆清除特征值(设置端点的状态)

02 01 0000 0082 0000

02 01 0000 0086 0000

02 01 0000 000f 0000

02 01 0000 0081 0000

02 01 0000 000a 0000

◆getlinecoding(获取波特率、数据、奇偶、结束位)

a1 21 0000 0005 0007  REQ_GET_LINE_CODING

回复:

00 10 0e 00 00 00 08

◆setlinestate (设置流控state)

21 22 0000 0005 0000

◆setlinecoding(设置流控配置)

21 20 0000 0005 0007

  • setup函数的实现:

_usb_device_register_service(_usbDeviceHandle, MV_USB_SERVICE_EP0, USB2DeviceControlProcessIdle);

static void USB2DeviceControlProcessIdle(void* handle, uint_8  type, boolean  setup, uint_8 direction, uint_8* buffer, uint_32 length, uint_8  error)

{

    if ( setup )

    {

        _usb_device_read_setup_data(handle, MV_USB_SERVICE_EP0, (UINT8*)&setupPacket);  //设备得到主机的数据

        uart_dump(&setupPacket,8);

        _usbDeviceDatabase.ep0.state = USB_DEVICE_EP0_STATE_SETUP;

        _usbDeviceDatabase.ep0.ctrl_setup_buff = (UINT8*)&setupPacket;

        _usbDeviceDatabase.ep0.crtl_trasnfers_cnt++;

        _usbDeviceDatabase.ep0.ep0_int_cnt++;

        if ( length < USB2_EP0_MAX_PACKET_SIZE )

        {

            _usbDeviceDatabase.ep0.state = USB_DEVICE_EP0_STATE_STATUS;

        }

    }

    else

    {

        if (length>=7)

        {

            MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "NON-SETUP, Length=%d Error=#%d Direction=%d, Value(hex): %02.2x %02.2x %02.2x %02.2x %02.2x %02.2x %02.2x\n",

            length, error, direction, (buffer)[0],(buffer)[1],(buffer)[2],(buffer)[3],(buffer)[4],(buffer)[5],(buffer)[6]);

        }

        else

        {

            MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "NON-SETUP, Length=%d Error=#%d Direction=%d\n", length, error, direction);

        }

    }

    switch (setupPacket.REQUESTTYPE & 0x60)   //主机输入的数据

    {

        case REQ_TYPE_STANDARD:      //标准访问

        {

            switch (setupPacket.REQUEST)

            {

                case REQ_GET_STATUS:

                {

                    mvUsbCh9GetStatus(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_GETSTAT\n");

                    break;

                }

                case REQ_CLEAR_FEATURE:

                {

                    mvUsbCh9ClearFeature(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_CLRADD\n");

                    break;

                }

                case REQ_SET_FEATURE:

                {

                    mvUsbCh9SetFeature(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_SETFEA\n");

                    break;

                }

                case REQ_SET_ADDRESS:        //设置设备地址

                {

                    mvUsbCh9SetAddress(handle, setup, &setupPacket);

                                               //USB_TRACE("sa\r\n");

                    USB2DeviceInitEps(handle);

                    mvUsbModemClearDummyFlag();

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_SETADR\n");

                    break;

                }

                case REQ_GET_DESCRIPTOR:   //获取描述符(设备、配置、字符)

                {

                    mvUsbCh9GetDescriptior(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_GETDSC\n");

                    usb_state = 1;

                    break;

                }

                case REQ_SET_DESCRIPTOR:

                {

                    mvUsbCh9SetDescriptior(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_SETDSC\n");

                    break;

                }

                case REQ_GET_CONFIGURATION:   //获取配置描述符

                {

                    mvUsbCh9GetConfig(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_GETCFG\n");

                    break;

                }

                case REQ_SET_CONFIGURATION:

                {

                    mvUsbCh9SetConfig(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_SETCFG\n");

                    break;

                }

                case REQ_GET_INTERFACE:  //获取接口描述符

                {

                    mvUsbCh9GetInterface(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_GETIF\n");

                    break;

                }

                case REQ_SET_INTERFACE:

                {

                    mvUsbCh9SetInterface(handle, setup, &setupPacket);

                    MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "STD_SETIF\n");

                    break;

                }

                default:

                {

                                               USB_TRACE("st1:%x,%x,%x,%x,%x,%d", setupPacket.REQUESTTYPE, setupPacket.REQUEST, setupPacket.VALUE, setupPacket.INDEX, setupPacket.LENGTH, setup);

                    _usb_device_stall_endpoint(handle, 0, 0);

                    break;

                }

            } /* Endswitch */

            break;

        }

        case REQ_TYPE_CLASS:  /* class specific request */

        {

            switch (setupPacket.REQUEST)

            {

                case REQ_SET_COMM_FEATURE:

                {

                    mvUsbCh9SetCommFeature(handle, setup, &setupPacket);

                    break;

                }

                case REQ_GET_COMM_FEATURE:

                {

                    mvUsbCh9GetCommFeature(handle, setup, &setupPacket);

                    break;

                }

                case REQ_SET_CONTROL_LINE_STATE:

                {

                    mvUsbCh9SetCtrlLineST(handle, setup, &setupPacket);

                    break;

                }

                case REQ_CLEAR_COMM_FEATURE:

                {

                    mvUsbCh9ClearCommFeature(handle, setup, &setupPacket);

                    break;

                }

                case REQ_SET_LINE_CODING:

                {

                    mvUsbCh9SetLineCode(handle, setup, &setupPacket);

                    break;

                }

                case REQ_GET_LINE_CODING:

                {

                    mvUsbCh9GetLineCode(handle, setup, &setupPacket);

                    break;

                }

#ifdef MV_USB2_MASS_STORAGE

                case REQ_GET_MAX_LUN:

                {

                    mvUsbCh9GetMaxLun(handle, setup, &setupPacket);

                    break;

                }

                case REQ_BOT_MSC_RESET:

                {

                    mvUsbCh9BotMscReset(handle, setup, &setupPacket);

                    break;

                }

#endif

                case REQ_SEND_ENCAPSULATED_COMMAND:

                {

                    mvUsbCh9EncapsulatedCmd(handle, setup, &setupPacket);

                    break;

                }

                case REQ_GET_ENCAPSULATED_RESPONSE:

                {

                    mvUsbCh9GetEncapsulatedRsp(handle, setup, &setupPacket);

                    break;

                }

                case REQ_SET_ETHERNET_MULTICAST_FILTERS:

                {

                    mvUsbCh9SetEthernetMulticastFilters( handle, setup, &setupPacket );

                    break;

                }

                case REQ_SET_ETHERNET_PACKET_FILTER:

                {

                    mvUsbCh9SetEthernetPacketFilter(handle, setup, &setupPacket);

                    break;

                }

//#ifdef MV_USB_MBIM

                case REQ_GET_NTB_PARAMETERS:

                {

                    mvUsbCh9GetNTBParameters(handle, setup, &setupPacket);

                    break;

                }

                case REQ_GET_NTB_INPUT_SIZE:

                {

                    mvUsbCh9GetNTBInputSize(handle, setup, &setupPacket);

                    break;

                }

                case REQ_SET_NTB_INPUT_SIZE:

                {

                    mvUsbCh9SetNTBInputSize(handle, setup, &setupPacket);

                    break;

                }

                case REQ_GET_NTB_FORMAT:

                {

                    mvUsbCh9GetNTBFormat(handle, setup, &setupPacket);

                    break;

                }

                case REQ_SET_NTB_FORMAT:

                {

                    mvUsbCh9SetNTBFormat(handle, setup, &setupPacket);

                    break;

                }

                case REQ_GET_CRC_MODE:

                {

                    mvUsbCh9GetCRCMode(handle, setup, &setupPacket);

                    break;

                }

                case REQ_SET_CRC_MODE:

                {

                    mvUsbCh9SetCRCMode(handle, setup, &setupPacket);

                    break;

                }

//#endif /* MV_USB_MBIM.  */

                case REQ_SET_NET_ADDRESS:

                {

                    mvUsbCh9SetNetAddress( handle, setup, &setupPacket );

                    break;

                }

                case REQ_GET_NET_ADDRESS:

                {

                    mvUsbCh9GetNetAddress( handle, setup, &setupPacket );

                    break;

                }

                case REQ_CLASS_SPECIFIC_RESERVED_5:

                {

                    if(setup)

                        mvUsbCh9SendEp0Data(handle, 0, 0);

                    break;

                }

                default:

                {

                                               USB_TRACE("st2:%x,%x,%x,%x,%x,%d", setupPacket.REQUESTTYPE, setupPacket.REQUEST, setupPacket.VALUE, setupPacket.INDEX, setupPacket.LENGTH, setup);

                    _usb_device_stall_endpoint(handle, 0, 0);

                    break;

                }

            }

            break;

        }

        case REQ_TYPE_VENDOR:

        {

            /* vendor specific request can be handled here*/

            //if(!ifAcatUsb)

            {

                //Add 0x22 for USB serial to finish enumeration process

                if(setupPacket.REQUEST==0x22)

                {

                    _usb_device_send_data(handle, 0, 0, 0);

                }

            }

            if ( direction == UDC_EP_DIR_OUT )

            {

                if (USB_DEVICE_EP0_GET_TRANSACTION_DIR(setupPacket.REQUESTTYPE) == USBCDevice_DataStageDirectionH2D) /* H2D direction */

                {

                    //prepare fields

                    if ( setup )

                    {

                        _usbDeviceDatabase.ep0.ctrl_out_data_stage_total_length = setupPacket.LENGTH;

                        if ( setupPacket.LENGTH == 0 )

                        {

                            if(_usbDeviceDatabase.vendorClassRequestNotifyFn)

                            {

                                USB_DEVICE_ASSERT(_usbDeviceDatabase.vendorClassRequestNotifyFn ); //must not be NULL

                                memcpy((char*)&vendorSetupPacket,(char *)&setupPacket, sizeof(SETUP_STRUCT));

                                vendorSetupPacket.p_data = NULL;

                                _usbDeviceDatabase.vendorClassRequestNotifyFn(&vendorSetupPacket);

                                MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "H2D - SETUP - vendorClassRequestNotifyFn called with setupPacket\n");

                            }

                            else

                            {

                                ErrorLogPrintf("vendorClassRequestNotifyFn is null, send zero packet.");

                                _usb_device_send_data(handle, 0, 0, 0);

                            }

                        }

                        else // setupPacket.LENGTH > 0) /* host only transmits setup packet, notify user so user can reply with ZLP */

                        {

                            USB_DEVICE_ASSERT(setupPacket.LENGTH <= USB_EP0_MAX_RX_TRANSFER_SIZE );    /* if assert need to enlarge ep0_out_data_buffer size*/

                            _usb_device_recv_data(_usbDeviceHandle, 0, _usbDeviceDatabase.ep0.ctrl_out_data_stage_buff, setupPacket.LENGTH);     /* Ack with ZLP. */

                            MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "H2D - SETUP - prepare recv OUT data (H2D) len = %d\n", setupPacket.LENGTH);

                        }

                    }

                    else

                    {     /* we arive here for Ack on OUT stage (that its length is > 0 */

                        if ( _usbDeviceDatabase.ep0.ctrl_out_data_stage_total_length == length)

                        {

                            memcpy((char *)&vendorSetupPacket,(char *)&setupPacket, sizeof(SETUP_STRUCT));

                            if ( length == 0)

                            {

                                vendorSetupPacket.p_data = NULL;

                            }

                            else

                            {

                                vendorSetupPacket.p_data = _usbDeviceDatabase.ep0.ctrl_out_data_stage_buff;

                            }

                            if(_usbDeviceDatabase.vendorClassRequestNotifyFn!= NULL)

                            {

                                USB_DEVICE_ASSERT(_usbDeviceDatabase.vendorClassRequestNotifyFn);

                                _usbDeviceDatabase.vendorClassRequestNotifyFn(&vendorSetupPacket);

                                MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "H2D - NON-setup - vendorClassRequestNotifyFn called with setup+DATA length=%d\n", length);

                            }

                            else

                            {

                                ErrorLogPrintf("vendorClassRequestNotifyFn is null, send zero packet.");

                                _usb_device_send_data(handle, 0, 0, 0);

                            }

                        }

                        else

                        {

                                                                 USB_TRACE("st3:%x,%x,%x,%x,%x,%d", setupPacket.REQUESTTYPE, setupPacket.REQUEST, setupPacket.VALUE, setupPacket.INDEX, setupPacket.LENGTH, setup);

                            MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "H2D - Non-setup - PROBLEM!!!!!\n");

                        }

                    }

                }

                else   /* D2H direction */

                {

                    if ( setup )

                    {

                        if(_usbDeviceDatabase.vendorClassRequestNotifyFn != NULL)

                        {

                            USB_DEVICE_ASSERT(_usbDeviceDatabase.vendorClassRequestNotifyFn ); //must not be NULL

                            memcpy((char*)&vendorSetupPacket,(char *)&setupPacket, sizeof(SETUP_STRUCT));

                            vendorSetupPacket.p_data = NULL;

                            //must notify upper layer SW & expect transmit

                            _usbDeviceDatabase.vendorClassRequestNotifyFn((USB_SetupCmdS*)&setupPacket);

                            MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "D2H - SETUP - call vendorClassRequestNotifyFn with setup packet\n");

                            if ( setupPacket.LENGTH )

                            {

                                waitForStatusAfterInStage = TRUE;  // Host should Ack after IN stage completes.

                            }

                        }

                        else

                        {

                            ErrorLogPrintf("vendorClassRequestNotifyFn is null, send zero packet.");

                            _usb_device_send_data(handle, 0, 0, 0);

                        }

                    }

                    else  /* IN stage */

                    {

                        // Note: preparation for ZLP Ack for IN stage which its length is > 0  is done in TransmitEndpoint API.

                        USB_DEVICE_ASSERT( waitForStatusAfterInStage );

                        waitForStatusAfterInStage = FALSE;

                        MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "D2H - NON-setup - Host ACK after IN stage\n");

                                                        USB_TRACE("\r\n NON \r\n");

                    }

                }

            }

            else

            {

                MV_USB_DEBUG_TRACE(MV_USB_DEBUG_FLAG_EP0, "ACK for length=%d\n", length);

            }

            break;

        }

        default:

        {

            if ( setup )

            {

                                     USB_TRACE("st4:%x,%x,%x,%x,%x,%d", setupPacket.REQUESTTYPE, setupPacket.REQUEST, setupPacket.VALUE, setupPacket.INDEX, setupPacket.LENGTH, setup);

                _usb_device_stall_endpoint(handle, 0, 0);

            }

            break;

        }

    } /* Endswitch */

    if ( !setup )

    {

        mvUsbProcessNonSetupData(handle, direction, buffer, length);

    }

    return;

}

枚举完成的记录

UsbIsEnumerated()

上一篇:tidb的组件ticdc传输数据到kafka


下一篇:2021-09-29 usb枚举和cdc的传输