stm32f4 USB项目开发详解 - 小龙1356 - 博客园 (cnblogs.com)
1、一个设备可以有多个配置,不同的配置对应不同的功能
比如,一个USB接口的CD-ROM,作为一个设备,
它具有两种功能,1读取光盘 和 2播放CD,所以有2个Configuration描述符
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接入执行过程:
- EHCI_STS_SUSPEND 0x100
清除usb的发送
- 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);
- EHCI_STS_PORT_CHANGE 0x4
使能端点
Resume
- 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()