/** ****************************************************************************** * @file usbd_msc_bot.c * @author MCD Application Team * @version V2.3.0 * @date 04-November-2014 * @brief This file provides all the BOT protocol core functions. ****************************************************************************** * @attention * *

© COPYRIGHT 2014 STMicroelectronics

* * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** * * Modifications by Robert Fisk */ /* Includes ------------------------------------------------------------------*/ #include "usbd_msc_bot.h" #include "usbd_msc.h" #include "usbd_msc_scsi.h" #include "usbd_ioreq.h" #include "build_config.h" #ifdef CONFIG_MASS_STORAGE_ENABLED /** @addtogroup STM32_USB_DEVICE_LIBRARY * @{ */ /** @defgroup MSC_BOT * @brief BOT protocol module * @{ */ /** @defgroup MSC_BOT_Private_TypesDefinitions * @{ */ /** * @} */ /** @defgroup MSC_BOT_Private_Defines * @{ */ /** * @} */ /** @defgroup MSC_BOT_Private_Macros * @{ */ /** * @} */ /** @defgroup MSC_BOT_Private_Variables * @{ */ USBD_HandleTypeDef *MSC_BOT_pdev; USBD_MSC_BOT_HandleTypeDef *MSC_BOT_hmsc; /** * @} */ /** @defgroup MSC_BOT_Private_FunctionPrototypes * @{ */ static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev); static void MSC_BOT_SendData (USBD_HandleTypeDef *pdev, uint8_t* pbuf, uint16_t len); static void MSC_BOT_Abort(USBD_HandleTypeDef *pdev); /** * @} */ /** @defgroup MSC_BOT_Private_Functions * @{ */ /** * @brief MSC_BOT_Init * Initialize the BOT Process * @param pdev: device instance * @retval None */ void MSC_BOT_Init (USBD_HandleTypeDef *pdev) { USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; hmsc->bot_state = USBD_BOT_IDLE; hmsc->bot_status = USBD_BOT_STATUS_NORMAL; hmsc->bot_packet = NULL; hmsc->last_test_unit_result = HAL_ERROR; hmsc->scsi_sense_tail = 0; hmsc->scsi_sense_head = 0; USBD_LL_FlushEP(pdev, MSC_EPOUT_ADDR); USBD_LL_FlushEP(pdev, MSC_EPIN_ADDR); /* Prapare EP to Receive First BOT Cmd */ USBD_LL_PrepareReceive (pdev, MSC_EPOUT_ADDR, (uint8_t *)&hmsc->cbw, USBD_BOT_CBW_LENGTH); } /** * @brief MSC_BOT_Reset * Reset the BOT Machine * @param pdev: device instance * @retval None */ void MSC_BOT_Reset (USBD_HandleTypeDef *pdev) { USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; hmsc->bot_state = USBD_BOT_IDLE; hmsc->bot_status = USBD_BOT_STATUS_RECOVERY; /* Prapare EP to Receive First BOT Cmd */ USBD_LL_PrepareReceive (pdev, MSC_EPOUT_ADDR, (uint8_t *)&hmsc->cbw, USBD_BOT_CBW_LENGTH); } /** * @brief MSC_BOT_DeInit * Deinitialize the BOT Machine * @param pdev: device instance * @retval None */ void MSC_BOT_DeInit (USBD_HandleTypeDef *pdev) { USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; hmsc->bot_state = USBD_BOT_IDLE; } /** * @brief MSC_BOT_DataIn * Handle BOT IN data stage * @param pdev: device instance * @param epnum: endpoint index * @retval None */ void MSC_BOT_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) { UNUSED(epnum); USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; switch (hmsc->bot_state) { case USBD_BOT_DATA_IN: MSC_BOT_pdev = pdev; SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0], MSC_BOT_DataIn_Callback); break; case USBD_BOT_SEND_DATA: case USBD_BOT_LAST_DATA_IN: MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED); break; default: break; } } void MSC_BOT_DataIn_Callback(int8_t result) { if (result < 0) { MSC_BOT_SendCSW (MSC_BOT_pdev, USBD_CSW_CMD_FAILED); } } /** * @brief MSC_BOT_DataOut * Process MSC OUT data * @param pdev: device instance * @param epnum: endpoint index * @retval None */ void MSC_BOT_DataOut (USBD_HandleTypeDef *pdev, uint8_t epnum) { UNUSED(epnum); USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; switch (hmsc->bot_state) { case USBD_BOT_IDLE: MSC_BOT_CBW_Decode(pdev); break; case USBD_BOT_DATA_OUT: MSC_BOT_pdev = pdev; SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0], MSC_BOT_DataOut_Callback); break; default: break; } } void MSC_BOT_DataOut_Callback(int8_t result) { if (result < 0) { MSC_BOT_SendCSW (MSC_BOT_pdev, USBD_CSW_CMD_FAILED); } } /** * @brief MSC_BOT_CBW_Decode * Decode the CBW command and set the BOT state machine accordingly * @param pdev: device instance * @retval None */ static void MSC_BOT_CBW_Decode (USBD_HandleTypeDef *pdev) { USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; hmsc->csw.dTag = hmsc->cbw.dTag; hmsc->csw.dDataResidue = hmsc->cbw.dDataLength; if ((USBD_LL_GetRxDataSize (pdev ,MSC_EPOUT_ADDR) != USBD_BOT_CBW_LENGTH) || (hmsc->cbw.dSignature != USBD_BOT_CBW_SIGNATURE)|| (hmsc->cbw.bLUN > 1) || (hmsc->cbw.bCBLength < 1) || (hmsc->cbw.bCBLength > 16)) { SCSI_SenseCode(pdev, hmsc->cbw.bLUN, ILLEGAL_REQUEST, INVALID_CDB); hmsc->bot_status = USBD_BOT_STATUS_ERROR; MSC_BOT_Abort(pdev); } else { MSC_BOT_pdev = pdev; MSC_BOT_hmsc = hmsc; SCSI_ProcessCmd(pdev, hmsc->cbw.bLUN, &hmsc->cbw.CB[0], MSC_BOT_CBW_Decode_Callback); } } void MSC_BOT_CBW_Decode_Callback(int8_t result) { if (result < 0) { if(MSC_BOT_hmsc->bot_state == USBD_BOT_NO_DATA) { MSC_BOT_SendCSW (MSC_BOT_pdev, USBD_CSW_CMD_FAILED); } else { MSC_BOT_Abort(MSC_BOT_pdev); } } /*Burst xfer handled internally*/ else if ((MSC_BOT_hmsc->bot_state != USBD_BOT_DATA_IN) && (MSC_BOT_hmsc->bot_state != USBD_BOT_DATA_OUT) && (MSC_BOT_hmsc->bot_state != USBD_BOT_LAST_DATA_IN)) { if (MSC_BOT_hmsc->bot_data_length > 0) { MSC_BOT_SendData(MSC_BOT_pdev, MSC_BOT_hmsc->bot_data, MSC_BOT_hmsc->bot_data_length); } else if (MSC_BOT_hmsc->bot_data_length == 0) { MSC_BOT_SendCSW (MSC_BOT_pdev, USBD_CSW_CMD_PASSED); } } } /** * @brief MSC_BOT_SendData * Send the requested data * @param pdev: device instance * @param buf: pointer to data buffer * @param len: Data Length * @retval None */ static void MSC_BOT_SendData(USBD_HandleTypeDef *pdev, uint8_t* buf, uint16_t len) { USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; len = MIN (hmsc->cbw.dDataLength, len); hmsc->csw.dDataResidue -= len; hmsc->csw.bStatus = USBD_CSW_CMD_PASSED; hmsc->bot_state = USBD_BOT_SEND_DATA; USBD_LL_Transmit (pdev, MSC_EPIN_ADDR, buf, len); } /** * @brief MSC_BOT_SendCSW * Send the Command Status Wrapper * @param pdev: device instance * @param status : CSW status * @retval None */ void MSC_BOT_SendCSW (USBD_HandleTypeDef *pdev, uint8_t CSW_Status) { USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; hmsc->csw.dSignature = USBD_BOT_CSW_SIGNATURE; hmsc->csw.bStatus = CSW_Status; hmsc->bot_state = USBD_BOT_IDLE; //De-register UpstreamPacket* from USB interface, //so we don't unintentionally free it on USB transaction completion. hmsc->bot_packet = NULL; USBD_LL_Transmit (pdev, MSC_EPIN_ADDR, (uint8_t *)&hmsc->csw, USBD_BOT_CSW_LENGTH); /* Prepare EP to Receive next Cmd */ USBD_LL_PrepareReceive (pdev, MSC_EPOUT_ADDR, (uint8_t *)&hmsc->cbw, USBD_BOT_CBW_LENGTH); } /** * @brief MSC_BOT_Abort * Abort the current transfer * @param pdev: device instance * @retval status */ static void MSC_BOT_Abort (USBD_HandleTypeDef *pdev) { USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; if ((hmsc->cbw.bmFlags == 0) && (hmsc->cbw.dDataLength != 0) && (hmsc->bot_status == USBD_BOT_STATUS_NORMAL) ) { USBD_LL_StallEP(pdev, MSC_EPOUT_ADDR ); } USBD_LL_StallEP(pdev, MSC_EPIN_ADDR); if(hmsc->bot_status == USBD_BOT_STATUS_ERROR) { USBD_LL_PrepareReceive (pdev, MSC_EPOUT_ADDR, (uint8_t *)&hmsc->cbw, USBD_BOT_CBW_LENGTH); } } /** * @brief MSC_BOT_CplClrFeature * Complete the clear feature request * @param pdev: device instance * @param epnum: endpoint index * @retval None */ void MSC_BOT_CplClrFeature (USBD_HandleTypeDef *pdev, uint8_t epnum) { USBD_MSC_BOT_HandleTypeDef *hmsc = (USBD_MSC_BOT_HandleTypeDef*)pdev->pClassData; if(hmsc->bot_status == USBD_BOT_STATUS_ERROR )/* Bad CBW Signature */ { USBD_LL_StallEP(pdev, MSC_EPIN_ADDR); hmsc->bot_status = USBD_BOT_STATUS_NORMAL; } else if(((epnum & 0x80) == 0x80) && ( hmsc->bot_status != USBD_BOT_STATUS_RECOVERY)) { MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_FAILED); } } #endif //#ifdef CONFIG_MASS_STORAGE_ENABLED /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/