STM32F407的USB类请求回调函数USBD_Class_cb_TypeDef
2022-06-17
708
0
前面介绍了获取描述会和USB设备状态的回调函数,这里界绍USB在实际使用过程中的USB请求通讯。这里还是以STM32F407的U盘为示例来说明。
STM32F407的USB类请求使用结构体USBD_Class_cb_TypeDef来整合回调函数。
typedef struct _Device_cb
{
uint8_t (*Init) (void *pdev , uint8_t cfgidx);
uint8_t (*DeInit) (void *pdev , uint8_t cfgidx);
/* Control Endpoints*/
uint8_t (*Setup) (void *pdev , USB_SETUP_REQ *req);
uint8_t (*EP0_TxSent) (void *pdev );
uint8_t (*EP0_RxReady) (void *pdev );
/* Class Specific Endpoints*/
uint8_t (*DataIn) (void *pdev , uint8_t epnum);
uint8_t (*DataOut) (void *pdev , uint8_t epnum);
uint8_t (*SOF) (void *pdev);
uint8_t (*IsoINIncomplete) (void *pdev);
uint8_t (*IsoOUTIncomplete) (void *pdev);
uint8_t *(*GetConfigDescriptor)( uint8_t speed , uint16_t *length);
#ifdef USB_OTG_HS_CORE
uint8_t *(*GetOtherConfigDescriptor)( uint8_t speed , uint16_t *length);
#endif
#ifdef USB_SUPPORT_USER_STRING_DESC
uint8_t *(*GetUsrStrDescriptor)( uint8_t speed ,uint8_t index, uint16_t *length);
#endif
} USBD_Class_cb_TypeDef;
相关的回调函数初始化为:
USBD_Class_cb_TypeDef USBD_MSC_cb =
{
USBD_MSC_Init,
USBD_MSC_DeInit,
USBD_MSC_Setup,
NULL, /*EP0_TxSent*/
NULL, /*EP0_RxReady*/
USBD_MSC_DataIn,
USBD_MSC_DataOut,
NULL, /*SOF */
NULL,
NULL,
USBD_MSC_GetCfgDesc,
#ifdef USB_OTG_HS_CORE
USBD_MSC_GetOtherCfgDesc,
#endif
};
USBD_MSC_Init
该函数用于设备工作后,对端点的初始化操作。
uint8_t USBD_MSC_Init (void *pdev,
uint8_t cfgidx)
{
USBD_MSC_DeInit(pdev , cfgidx );
/* Open EP IN */
DCD_EP_Open(pdev,
MSC_IN_EP,
MSC_EPIN_SIZE,
USB_OTG_EP_BULK);
/* Open EP OUT */
DCD_EP_Open(pdev,
MSC_OUT_EP,
MSC_EPOUT_SIZE,
USB_OTG_EP_BULK);
/* Init the BOT layer */
MSC_BOT_Init(pdev);
return USBD_OK;
}
cfgidx为选择配置描述符的ID。这里为USB-BOTU盘设备,故初始化BULK传输的输入和输出端点,最后初始化U盘.
BOT的U盘支持UFI命令,这里使用结构体USBD_STORAGE_cb_TypeDef来整合。
typedef struct _USBD_STORAGE
{
int8_t (* Init) (uint8_t lun);
int8_t (* GetCapacity) (uint8_t lun, uint32_t *block_num, uint32_t *block_size);
int8_t (* IsReady) (uint8_t lun);
int8_t (* IsWriteProtected) (uint8_t lun);
int8_t (* Read) (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
int8_t (* Write)(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
int8_t (* GetMaxLun)(void);
int8_t *pInquiry;
}USBD_STORAGE_cb_TypeDef;
USBD_STORAGE_cb_TypeDef USBD_MICRO_SDIO_fops =
{
STORAGE_Init,
STORAGE_GetCapacity,
STORAGE_IsReady,
STORAGE_IsWriteProtected,
STORAGE_Read,
STORAGE_Write,
STORAGE_GetMaxLun,
(int8_t *)STORAGE_Inquirydata,
};
USBD_STORAGE_cb_TypeDef *USBD_STORAGE_fops=&USBD_MICRO_SDIO_fops;//Ö¸ÏòUSBD_MICRO_SDIO_fops½á¹¹Ìå.
可以看到,这里对应UFI的相关命令回调函数。
关于U盘的UFI BOT命令,详参见站站的http://www.usbzh.com/article/forum-57.html
USBD_MSC_DeInit
反初始化。
uint8_t USBD_MSC_DeInit (void *pdev,
uint8_t cfgidx)
{
/* Close MSC EPs */
DCD_EP_Close (pdev , MSC_IN_EP);
DCD_EP_Close (pdev , MSC_OUT_EP);
/* Un Init the BOT layer */
MSC_BOT_DeInit(pdev);
return USBD_OK;
}
USBD_MSC_Setup
SETUP令牌包,其实就是U盘的类特定请求,如BOT_GET_MAX_LUN等。
uint8_t USBD_MSC_Setup (void *pdev, USB_SETUP_REQ *req)
{
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
/* Class request */
case USB_REQ_TYPE_CLASS :
switch (req->bRequest)
{
case BOT_GET_MAX_LUN :
if((req->wValue == 0) &&
(req->wLength == 1) &&
((req->bmRequest & 0x80) == 0x80))
{
USBD_MSC_MaxLun = USBD_STORAGE_fops->GetMaxLun();
if(USBD_MSC_MaxLun > 0)
{
USBD_CtlSendData (pdev,
&USBD_MSC_MaxLun,
1);
}
else
{
USBD_CtlError(pdev , req);
return USBD_FAIL;
}
}
else
{
USBD_CtlError(pdev , req);
return USBD_FAIL;
}
break;
case BOT_RESET :
if((req->wValue == 0) &&
(req->wLength == 0) &&
((req->bmRequest & 0x80) != 0x80))
{
MSC_BOT_Reset(pdev);
}
else
{
USBD_CtlError(pdev , req);
return USBD_FAIL;
}
break;
default:
USBD_CtlError(pdev , req);
return USBD_FAIL;
}
break;
/* Interface & Endpoint request */
case USB_REQ_TYPE_STANDARD:
switch (req->bRequest)
{
case USB_REQ_GET_INTERFACE :
USBD_CtlSendData (pdev,
&USBD_MSC_AltSet,
1);
break;
case USB_REQ_SET_INTERFACE :
USBD_MSC_AltSet = (uint8_t)(req->wValue);
break;
case USB_REQ_CLEAR_FEATURE:
/* Flush the FIFO and Clear the stall status */
DCD_EP_Flush(pdev, (uint8_t)req->wIndex);
/* Re-activate the EP */
DCD_EP_Close (pdev , (uint8_t)req->wIndex);
if((((uint8_t)req->wIndex) & 0x80) == 0x80)
{
DCD_EP_Open(pdev,
((uint8_t)req->wIndex),
MSC_EPIN_SIZE,
USB_OTG_EP_BULK);
}
else
{
DCD_EP_Open(pdev,
((uint8_t)req->wIndex),
MSC_EPOUT_SIZE,
USB_OTG_EP_BULK);
}
/* Handle BOT error */
MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex);
break;
}
break;
default:
break;
}
return USBD_OK;
}
这里应关注USB_REQ_CLEAR_FEATURE,可以看到当设备的端点有问题时,主机使用CLEAR_FEATURE清除端点,这里一般执行端点的关闭和重新打开。
USBD_MSC_DataIn
输入端点的回调,即设备的BULK传输发送数据到主机。
uint8_t USBD_MSC_DataIn (void *pdev,
uint8_t epnum)
{
MSC_BOT_DataIn(pdev , epnum);
return USBD_OK;
}
void MSC_BOT_DataIn (USB_OTG_CORE_HANDLE *pdev,
uint8_t epnum)
{
switch (MSC_BOT_State)
{
case BOT_DATA_IN:
if(SCSI_ProcessCmd(pdev,
MSC_BOT_cbw.bLUN,
&MSC_BOT_cbw.CB[0]) < 0)
{
MSC_BOT_SendCSW (pdev, CSW_CMD_FAILED);
}
break;
case BOT_SEND_DATA:
case BOT_LAST_DATA_IN:
MSC_BOT_SendCSW (pdev, CSW_CMD_PASSED);
break;
default:
break;
}
}
USBD_MSC_DataOut
端点输出数据,即主机发送数据到设备。如CBW等。
uint8_t USBD_MSC_DataOut (void *pdev,
uint8_t epnum)
{
MSC_BOT_DataOut(pdev , epnum);
return USBD_OK;
}
void MSC_BOT_DataOut (USB_OTG_CORE_HANDLE *pdev,
uint8_t epnum)
{
switch (MSC_BOT_State)
{
case BOT_IDLE:
MSC_BOT_CBW_Decode(pdev);
break;
case BOT_DATA_OUT:
if(SCSI_ProcessCmd(pdev,
MSC_BOT_cbw.bLUN,
&MSC_BOT_cbw.CB[0]) < 0)
{
MSC_BOT_SendCSW (pdev, CSW_CMD_FAILED);
}
break;
default:
break;
}
}
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936