/** * @brief USBH_MSC_HandleBOTXfer * This function manages the different states of BOT transfer and * updates the status to upper layer. * @param None * @retval None * */ void USBH_MSC_HandleBOTXfer (USB_OTG_CORE_HANDLE *pdev ,USBH_HOST *phost) { uint8_t xferDirection, index; static uint32_t remainingDataLength; static uint8_t *datapointer , *datapointer_prev; static uint8_t error_direction; USBH_Status status; URB_STATE URB_Status = URB_IDLE; if(HCD_IsDeviceConnected(pdev)) { switch (USBH_MSC_BOTXferParam.BOTState) { case USBH_MSC_SEND_CBW: /* send CBW */ USBH_BulkSendData (pdev, &USBH_MSC_CBWData.CBWArray[0], USBH_MSC_BOT_CBW_PACKET_LENGTH , MSC_Machine.hc_num_out); USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_SEND_CBW; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_SENT_CBW; break; case USBH_MSC_SENT_CBW: URB_Status = HCD_GetURB_State(pdev , MSC_Machine.hc_num_out); if(URB_Status == URB_DONE) { BOTStallErrorCount = 0; USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_SENT_CBW; /* If the CBW Pkt is sent successful, then change the state */ xferDirection = (USBH_MSC_CBWData.field.CBWFlags & USB_REQ_DIR_MASK); if ( USBH_MSC_CBWData.field.CBWTransferLength != 0 ) { remainingDataLength = USBH_MSC_CBWData.field.CBWTransferLength ; datapointer = USBH_MSC_BOTXferParam.pRxTxBuff; datapointer_prev = datapointer; /* If there is Data Transfer Stage */ if (xferDirection == USB_D2H) { /* Data Direction is IN */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_DATAIN_STATE; } else { /* Data Direction is OUT */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_DATAOUT_STATE; } } else {/* If there is NO Data Transfer Stage */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE; } } else if(URB_Status == URB_NOTREADY) { USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp; } else if(URB_Status == URB_STALL) { error_direction = USBH_MSC_DIR_OUT; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_OUT; } break; case USBH_MSC_BOT_DATAIN_STATE: URB_Status = HCD_GetURB_State(pdev , MSC_Machine.hc_num_in); /* BOT DATA IN stage */ if((URB_Status == URB_DONE) ||(USBH_MSC_BOTXferParam.BOTStateBkp != USBH_MSC_BOT_DATAIN_STATE)) { BOTStallErrorCount = 0; USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_BOT_DATAIN_STATE; if(remainingDataLength > MSC_Machine.MSBulkInEpSize) { USBH_BulkReceiveData (pdev, datapointer, MSC_Machine.MSBulkInEpSize , MSC_Machine.hc_num_in); remainingDataLength -= MSC_Machine.MSBulkInEpSize; datapointer = datapointer + MSC_Machine.MSBulkInEpSize; } else if ( remainingDataLength == 0) { /* If value was 0, and successful transfer, then change the state */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE; } else { USBH_BulkReceiveData (pdev, datapointer, remainingDataLength , MSC_Machine.hc_num_in); remainingDataLength = 0; /* Reset this value and keep in same state */ } } else if(URB_Status == URB_STALL) { /* This is Data Stage STALL Condition */ error_direction = USBH_MSC_DIR_IN; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_IN; /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 6.7.2 Host expects to receive data from the device 3. On a STALL condition receiving data, then: The host shall accept the data received. The host shall clear the Bulk-In pipe. 4. The host shall attempt to receive a CSW. USBH_MSC_BOTXferParam.BOTStateBkp is used to switch to the Original state after the ClearFeature Command is issued. */ USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE; } break; case USBH_MSC_BOT_DATAOUT_STATE: /* BOT DATA OUT stage */ URB_Status = HCD_GetURB_State(pdev , MSC_Machine.hc_num_out); if(URB_Status == URB_DONE) { BOTStallErrorCount = 0; USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_BOT_DATAOUT_STATE; if(remainingDataLength > MSC_Machine.MSBulkOutEpSize) { USBH_BulkSendData (pdev, datapointer, MSC_Machine.MSBulkOutEpSize , MSC_Machine.hc_num_out); datapointer_prev = datapointer; datapointer = datapointer + MSC_Machine.MSBulkOutEpSize; remainingDataLength = remainingDataLength - MSC_Machine.MSBulkOutEpSize; } else if ( remainingDataLength == 0) { /* If value was 0, and successful transfer, then change the state */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_RECEIVE_CSW_STATE; } else { USBH_BulkSendData (pdev, datapointer, remainingDataLength , MSC_Machine.hc_num_out); remainingDataLength = 0; /* Reset this value and keep in same state */ } } else if(URB_Status == URB_NOTREADY) { if(datapointer != datapointer_prev) { USBH_BulkSendData (pdev, (datapointer - MSC_Machine.MSBulkOutEpSize), MSC_Machine.MSBulkOutEpSize , MSC_Machine.hc_num_out); } else { USBH_BulkSendData (pdev, datapointer, MSC_Machine.MSBulkOutEpSize , MSC_Machine.hc_num_out); } } else if(URB_Status == URB_STALL) { error_direction = USBH_MSC_DIR_OUT; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_OUT; /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 6.7.3 Ho - Host expects to send data to the device 3. On a STALL condition sending data, then: " The host shall clear the Bulk-Out pipe. 4. The host shall attempt to receive a CSW. The Above statement will do the clear the Bulk-Out pipe. The Below statement will help in Getting the CSW. USBH_MSC_BOTXferParam.BOTStateBkp is used to switch to the Original state after the ClearFeature Command is issued. */ USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE; } break; case USBH_MSC_RECEIVE_CSW_STATE: /* BOT CSW stage */ /* NOTE: We cannot reset the BOTStallErrorCount here as it may come from the clearFeature from previous command */ USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE; USBH_MSC_BOTXferParam.pRxTxBuff = USBH_MSC_CSWData.CSWArray; USBH_MSC_BOTXferParam.DataLength = USBH_MSC_CSW_MAX_LENGTH; for(index = USBH_MSC_CSW_LENGTH; index != 0; index--) { USBH_MSC_CSWData.CSWArray[index] = 0; } USBH_MSC_CSWData.CSWArray[0] = 0; USBH_BulkReceiveData (pdev, USBH_MSC_BOTXferParam.pRxTxBuff, USBH_MSC_CSW_MAX_LENGTH , MSC_Machine.hc_num_in); USBH_MSC_BOTXferParam.BOTState = USBH_MSC_DECODE_CSW; break; case USBH_MSC_DECODE_CSW: URB_Status = HCD_GetURB_State(pdev , MSC_Machine.hc_num_in); /* Decode CSW */ if(URB_Status == URB_DONE) { BOTStallErrorCount = 0; USBH_MSC_BOTXferParam.BOTStateBkp = USBH_MSC_RECEIVE_CSW_STATE; USBH_MSC_BOTXferParam.MSCState = USBH_MSC_BOTXferParam.MSCStateCurrent ; USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_DecodeCSW(pdev , phost); } else if(URB_Status == URB_STALL) { error_direction = USBH_MSC_DIR_IN; USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_IN; } break; case USBH_MSC_BOT_ERROR_IN: status = USBH_MSC_BOT_Abort(pdev, phost, USBH_MSC_DIR_IN); if (status == USBH_OK) { /* Check if the error was due in Both the directions */ if (error_direction == USBH_MSC_BOTH_DIR) {/* If Both directions are Needed, Switch to OUT Direction */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOT_ERROR_OUT; } else { /* Switch Back to the Original State, In many cases this will be USBH_MSC_RECEIVE_CSW_STATE state */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp; } } else if (status == USBH_UNRECOVERED_ERROR) { /* This means that there is a STALL Error limit, Do Reset Recovery */ USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_PHASE_ERROR; } break; case USBH_MSC_BOT_ERROR_OUT: status = USBH_MSC_BOT_Abort(pdev, phost, USBH_MSC_DIR_OUT); if ( status == USBH_OK) { /* Switch Back to the Original State */ USBH_MSC_BOTXferParam.BOTState = USBH_MSC_BOTXferParam.BOTStateBkp; } else if (status == USBH_UNRECOVERED_ERROR) { /* This means that there is a STALL Error limit, Do Reset Recovery */ USBH_MSC_BOTXferParam.BOTXferStatus = USBH_MSC_PHASE_ERROR; } break; default: break; } } }
/** * @brief USBH_MSC_BOT_Process * The function handle the BOT protocol. * @param phost: Host handle * @param lun: Logical Unit Number * @retval USBH Status */ USBH_StatusTypeDef USBH_MSC_BOT_Process (USBH_HandleTypeDef *phost, uint8_t lun) { USBH_StatusTypeDef status = USBH_BUSY; USBH_StatusTypeDef error = USBH_BUSY; BOT_CSWStatusTypeDef CSW_Status = BOT_CSW_CMD_FAILED; USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE; MSC_HandleTypeDef *MSC_Handle = phost->pActiveClass->pData; uint8_t toggle = 0; switch (MSC_Handle->hbot.state) { case BOT_SEND_CBW: MSC_Handle->hbot.cbw.field.LUN = lun; MSC_Handle->hbot.state = BOT_SEND_CBW_WAIT; USBH_BulkSendData (phost, MSC_Handle->hbot.cbw.data, BOT_CBW_LENGTH, MSC_Handle->OutPipe, 1); break; case BOT_SEND_CBW_WAIT: URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe); if(URB_Status == USBH_URB_DONE) { if ( MSC_Handle->hbot.cbw.field.DataTransferLength != 0 ) { /* If there is Data Transfer Stage */ if (((MSC_Handle->hbot.cbw.field.Flags) & USB_REQ_DIR_MASK) == USB_D2H) { /* Data Direction is IN */ MSC_Handle->hbot.state = BOT_DATA_IN; } else { /* Data Direction is OUT */ MSC_Handle->hbot.state = BOT_DATA_OUT; } } else {/* If there is NO Data Transfer Stage */ MSC_Handle->hbot.state = BOT_RECEIVE_CSW; } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } else if(URB_Status == USBH_URB_NOTREADY) { /* Re-send CBW */ MSC_Handle->hbot.state = BOT_SEND_CBW; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } else if(URB_Status == USBH_URB_STALL) { MSC_Handle->hbot.state = BOT_ERROR_OUT; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } break; case BOT_DATA_IN: /* Send first packet */ USBH_BulkReceiveData (phost, MSC_Handle->hbot.pbuf, MSC_Handle->InEpSize , MSC_Handle->InPipe); MSC_Handle->hbot.state = BOT_DATA_IN_WAIT; break; case BOT_DATA_IN_WAIT: URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe); if(URB_Status == USBH_URB_DONE) { /* Adjudt Data pointer and data length */ if(MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->InEpSize) { MSC_Handle->hbot.pbuf += MSC_Handle->InEpSize; MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->InEpSize; } else { MSC_Handle->hbot.cbw.field.DataTransferLength = 0; } /* More Data To be Received */ if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0) { /* Send next packet */ USBH_BulkReceiveData (phost, MSC_Handle->hbot.pbuf, MSC_Handle->InEpSize , MSC_Handle->InPipe); } else { /* If value was 0, and successful transfer, then change the state */ MSC_Handle->hbot.state = BOT_RECEIVE_CSW; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } } else if(URB_Status == USBH_URB_STALL) { /* This is Data IN Stage STALL Condition */ MSC_Handle->hbot.state = BOT_ERROR_IN; /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 6.7.2 Host expects to receive data from the device 3. On a STALL condition receiving data, then: The host shall accept the data received. The host shall clear the Bulk-In pipe. 4. The host shall attempt to receive a CSW.*/ #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } break; case BOT_DATA_OUT: USBH_BulkSendData (phost, MSC_Handle->hbot.pbuf, MSC_Handle->OutEpSize , MSC_Handle->OutPipe, 1); MSC_Handle->hbot.state = BOT_DATA_OUT_WAIT; break; case BOT_DATA_OUT_WAIT: URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->OutPipe); if(URB_Status == USBH_URB_DONE) { /* Adjudt Data pointer and data length */ if(MSC_Handle->hbot.cbw.field.DataTransferLength > MSC_Handle->OutEpSize) { MSC_Handle->hbot.pbuf += MSC_Handle->OutEpSize; MSC_Handle->hbot.cbw.field.DataTransferLength -= MSC_Handle->OutEpSize; } else { MSC_Handle->hbot.cbw.field.DataTransferLength = 0; } /* More Data To be Sent */ if(MSC_Handle->hbot.cbw.field.DataTransferLength > 0) { USBH_BulkSendData (phost, MSC_Handle->hbot.pbuf, MSC_Handle->OutEpSize , MSC_Handle->OutPipe, 1); } else { /* If value was 0, and successful transfer, then change the state */ MSC_Handle->hbot.state = BOT_RECEIVE_CSW; } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } else if(URB_Status == USBH_URB_NOTREADY) { /* Re-send same data */ MSC_Handle->hbot.state = BOT_DATA_OUT; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } else if(URB_Status == USBH_URB_STALL) { MSC_Handle->hbot.state = BOT_ERROR_OUT; /* Refer to USB Mass-Storage Class : BOT (www.usb.org) 6.7.3 Ho - Host expects to send data to the device 3. On a STALL condition sending data, then: " The host shall clear the Bulk-Out pipe. 4. The host shall attempt to receive a CSW. */ #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } break; case BOT_RECEIVE_CSW: USBH_BulkReceiveData (phost, MSC_Handle->hbot.csw.data, BOT_CSW_LENGTH , MSC_Handle->InPipe); MSC_Handle->hbot.state = BOT_RECEIVE_CSW_WAIT; break; case BOT_RECEIVE_CSW_WAIT: URB_Status = USBH_LL_GetURBState(phost, MSC_Handle->InPipe); /* Decode CSW */ if(URB_Status == USBH_URB_DONE) { MSC_Handle->hbot.state = BOT_SEND_CBW; MSC_Handle->hbot.cmd_state = BOT_CMD_SEND; CSW_Status = USBH_MSC_DecodeCSW(phost); if(CSW_Status == BOT_CSW_CMD_PASSED) { status = USBH_OK; } else { status = USBH_FAIL; } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } else if(URB_Status == USBH_URB_STALL) { MSC_Handle->hbot.state = BOT_ERROR_IN; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_URB_EVENT, 0); #endif } break; case BOT_ERROR_IN: error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_IN); if (error == USBH_OK) { MSC_Handle->hbot.state = BOT_RECEIVE_CSW; } else if (error == USBH_UNRECOVERED_ERROR) { /* This means that there is a STALL Error limit, Do Reset Recovery */ MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR; } break; case BOT_ERROR_OUT: error = USBH_MSC_BOT_Abort(phost, lun, BOT_DIR_OUT); if ( error == USBH_OK) { toggle = USBH_LL_GetToggle(phost, MSC_Handle->OutPipe); USBH_LL_SetToggle(phost, MSC_Handle->OutPipe, 1- toggle); USBH_LL_SetToggle(phost, MSC_Handle->InPipe, 0); MSC_Handle->hbot.state = BOT_ERROR_IN; } else if (error == USBH_UNRECOVERED_ERROR) { MSC_Handle->hbot.state = BOT_UNRECOVERED_ERROR; } break; case BOT_UNRECOVERED_ERROR: status = USBH_MSC_BOT_REQ_Reset(phost); if ( status == USBH_OK) { MSC_Handle->hbot.state = BOT_SEND_CBW; } break; default: break; } return status; }