/** ****************************************************************************** * @file usbh_msc.c * @author MCD Application Team * @version V3.2.1 * @date 26-June-2015 * @brief This file implements the MSC class driver functions * =================================================================== * MSC Class Description * =================================================================== * This module manages the MSC class V1.0 following the "Universal * Serial Bus Mass Storage Class (MSC) Bulk-Only Transport (BOT) Version 1.0 * Sep. 31, 1999". * This driver implements the following aspects of the specification: * - Bulk-Only Transport protocol * - Subclass : SCSI transparent command set (ref. SCSI Primary Commands - 3 (SPC-3)) * * @endverbatim * ****************************************************************************** * @attention * *

© COPYRIGHT 2015 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 "usbh_msc.h" #include "usbh_msc_bot.h" #include "usbh_msc_scsi.h" #include "interrupts.h" #include "build_config.h" #ifdef CONFIG_MASS_STORAGE_ENABLED /** @addtogroup USBH_LIB * @{ */ /** @addtogroup USBH_CLASS * @{ */ /** @addtogroup USBH_MSC_CLASS * @{ */ /** @defgroup USBH_MSC_CORE * @brief This file includes the mass storage related functions * @{ */ /** @defgroup USBH_MSC_CORE_Private_TypesDefinitions * @{ */ /** * @} */ /** @defgroup USBH_MSC_CORE_Private_Defines * @{ */ /** * @} */ /** @defgroup USBH_MSC_CORE_Private_Macros * @{ */ /** * @} */ /** @defgroup USBH_MSC_CORE_Private_Variables * @{ */ /** * @} */ /** @defgroup USBH_MSC_CORE_Private_FunctionPrototypes * @{ */ static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost); static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun); USBH_ClassTypeDef USBH_msc = { "MSC", USB_MSC_CLASS, USBH_MSC_InterfaceInit, USBH_MSC_InterfaceDeInit, USBH_MSC_ClassRequest, USBH_MSC_Process, USBH_MSC_SOFProcess, NULL, }; /** * @} */ /** @defgroup USBH_MSC_CORE_Exported_Variables * @{ */ /** * @} */ /** @defgroup USBH_MSC_CORE_Private_Functions * @{ */ /** * @brief USBH_MSC_InterfaceInit * The function init the MSC class. * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_MSC_InterfaceInit (USBH_HandleTypeDef *phost) { uint8_t interface = 0; USBH_StatusTypeDef status = USBH_FAIL ; MSC_HandleTypeDef *MSC_Handle; interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, 0xFF, MSC_BOT);//MSC_TRANSPARENT, MSC_BOT); //Ignore subclass?!! if(interface == 0xFF) /* Not Valid Interface */ { USBH_DbgLog ("Cannot Find the interface for %s class.", phost->pActiveClass->Name); status = USBH_FAIL; } else { USBH_SelectInterface (phost, interface); phost->pActiveClass->pData = (MSC_HandleTypeDef *)USBH_malloc (sizeof(MSC_HandleTypeDef)); MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress & 0x80) { MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress); MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize; } else { MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].bEndpointAddress); MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[0].wMaxPacketSize; } if(phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress & 0x80) { MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress); MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize; } else { MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].bEndpointAddress); MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[phost->device.current_interface].Ep_Desc[1].wMaxPacketSize; } MSC_Handle->current_lun = 0; MSC_Handle->rw_lun = 0; MSC_Handle->state = MSC_INIT; MSC_Handle->error = MSC_OK; MSC_Handle->req_state = MSC_REQ_IDLE; MSC_Handle->OutPipe = USBH_AllocPipe(phost, MSC_Handle->OutEp); MSC_Handle->InPipe = USBH_AllocPipe(phost, MSC_Handle->InEp); MSC_Handle->RdWrCompleteCallback = NULL; USBH_MSC_BOT_Init(phost); /* De-Initialize LUNs information */ USBH_memset(MSC_Handle->unit, 0, sizeof(MSC_Handle->unit)); /* Open the new channels */ USBH_OpenPipe (phost, MSC_Handle->OutPipe, MSC_Handle->OutEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, MSC_Handle->OutEpSize); USBH_OpenPipe (phost, MSC_Handle->InPipe, MSC_Handle->InEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, MSC_Handle->InEpSize); USBH_LL_SetToggle (phost, MSC_Handle->InPipe,0); USBH_LL_SetToggle (phost, MSC_Handle->OutPipe,0); status = USBH_OK; } return status; } /** * @brief USBH_MSC_InterfaceDeInit * The function DeInit the Pipes used for the MSC class. * @param phost: Host handle * @retval USBH Status */ USBH_StatusTypeDef USBH_MSC_InterfaceDeInit (USBH_HandleTypeDef *phost) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if ( MSC_Handle->OutPipe) { USBH_ClosePipe(phost, MSC_Handle->OutPipe); USBH_FreePipe (phost, MSC_Handle->OutPipe); MSC_Handle->OutPipe = 0; /* Reset the Channel as Free */ } if ( MSC_Handle->InPipe) { USBH_ClosePipe(phost, MSC_Handle->InPipe); USBH_FreePipe (phost, MSC_Handle->InPipe); MSC_Handle->InPipe = 0; /* Reset the Channel as Free */ } if(phost->pActiveClass->pData) { USBH_free (phost->pActiveClass->pData); phost->pActiveClass->pData = 0; } return USBH_OK; } /** * @brief USBH_MSC_ClassRequest * The function is responsible for handling Standard requests * for MSC class. * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_MSC_ClassRequest(USBH_HandleTypeDef *phost) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; USBH_StatusTypeDef status = USBH_BUSY; /* Switch MSC REQ state machine */ switch (MSC_Handle->req_state) { case MSC_REQ_IDLE: MSC_Handle->timeout = HAL_GetTick(); MSC_Handle->req_state = MSC_REQ_STARTUP_DELAY; break; case MSC_REQ_STARTUP_DELAY: if ((HAL_GetTick() - MSC_Handle->timeout) > MSC_SAMSUNG_STARTUP_DELAY_MS) { MSC_Handle->req_state = MSC_REQ_GET_MAX_LUN; } break; case MSC_REQ_GET_MAX_LUN: /* Issue GetMaxLUN request */ status = USBH_MSC_BOT_REQ_GetMaxLUN(phost, (uint8_t *)&MSC_Handle->max_lun); /* When devices do not support the GetMaxLun request, this should be considred as only one logical unit is supported */ if(status == USBH_NOT_SUPPORTED) { MSC_Handle->max_lun = 0; status = USBH_OK; } if(status == USBH_OK) { MSC_Handle->max_lun = (uint8_t )(MSC_Handle->max_lun) + 1; USBH_UsrLog ("Number of supported LUN: %lu", (int32_t)(MSC_Handle->max_lun)); if (MSC_Handle->max_lun > MAX_SUPPORTED_LUN) { MSC_Handle->max_lun = MAX_SUPPORTED_LUN; } MSC_Handle->req_state = MSC_REQ_IDLE; } break; case MSC_REQ_ERROR : /* a Clear Feature should be issued here */ if(USBH_ClrFeature(phost, 0x00) == USBH_OK) { MSC_Handle->req_state = MSC_Handle->prev_req_state; } break; default: break; } return status; } /** * @brief USBH_MSC_Process * The function is for managing state machine for MSC data transfers * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_MSC_Process(USBH_HandleTypeDef *phost) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; USBH_StatusTypeDef error = USBH_BUSY ; USBH_StatusTypeDef scsi_status = USBH_BUSY ; USBH_StatusTypeDef ready_status = USBH_BUSY ; switch (MSC_Handle->state) { case MSC_INIT: if(MSC_Handle->current_lun < MSC_Handle->max_lun) { MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY; /* Switch MSC REQ state machine */ switch (MSC_Handle->unit[MSC_Handle->current_lun].state) { case MSC_INIT: USBH_UsrLog ("LUN #%d: ", MSC_Handle->current_lun); MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_INQUIRY; MSC_Handle->timeout = phost->Timer; //Fallthrough case MSC_READ_INQUIRY: scsi_status = USBH_MSC_SCSI_Inquiry(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].inquiry); if( scsi_status == USBH_OK) { USBH_UsrLog ("Inquiry Vendor : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.vendor_id); USBH_UsrLog ("Inquiry Product : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.product_id); USBH_UsrLog ("Inquiry Version : %s", MSC_Handle->unit[MSC_Handle->current_lun].inquiry.revision_id); MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY; } if( scsi_status == USBH_FAIL) { MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE; } else if(scsi_status == USBH_UNRECOVERED_ERROR) { MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR; } break; case MSC_TEST_UNIT_READY: ready_status = USBH_MSC_SCSI_TestUnitReady(phost, MSC_Handle->current_lun); if( ready_status == USBH_OK) { if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_OK) { MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1; USBH_UsrLog ("MSC Device ready"); } else { MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0; } MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_READ_CAPACITY10; MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK; MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_OK; } if( ready_status == USBH_FAIL) { /* Media not ready, so try to check again during 10s */ if( MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state != USBH_FAIL) { MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 1; USBH_UsrLog ("MSC Device NOT ready"); } else { MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0; } MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE; MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_NOT_READY; MSC_Handle->unit[MSC_Handle->current_lun].prev_ready_state = USBH_FAIL; } else if(ready_status == USBH_UNRECOVERED_ERROR) { MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR; } break; case MSC_READ_CAPACITY10: scsi_status = USBH_MSC_SCSI_ReadCapacity(phost,MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].capacity) ; if(scsi_status == USBH_OK) { if(MSC_Handle->unit[MSC_Handle->current_lun].state_changed == 1) { USBH_UsrLog ("MSC Device capacity : %lu Bytes", \ (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr * MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size)); USBH_UsrLog ("Block number : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_nbr)); USBH_UsrLog ("Block Size : %lu", (int32_t)(MSC_Handle->unit[MSC_Handle->current_lun].capacity.block_size)); } MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_OK; MSC_Handle->current_lun++; } else if( scsi_status == USBH_FAIL) { MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE; } else if(scsi_status == USBH_UNRECOVERED_ERROR) { MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR; } break; case MSC_REQUEST_SENSE: scsi_status = USBH_MSC_SCSI_RequestSense(phost, MSC_Handle->current_lun, &MSC_Handle->unit[MSC_Handle->current_lun].sense); if( scsi_status == USBH_OK) { if((MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_UNIT_ATTENTION) || (MSC_Handle->unit[MSC_Handle->current_lun].sense.key == SCSI_SENSE_KEY_NOT_READY) ) { if((HAL_GetTick() - MSC_Handle->timeout) < MSC_STARTUP_TIMEOUT_MS) { MSC_Handle->retry_timeout = HAL_GetTick(); MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_REQUEST_SENSE_WAIT_RETRY; break; } } USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.key); USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.asc); USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[MSC_Handle->current_lun].sense.ascq); MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; MSC_Handle->current_lun++; } if( scsi_status == USBH_FAIL) { USBH_UsrLog ("MSC Device NOT ready"); MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_UNRECOVERED_ERROR; } else if(scsi_status == USBH_UNRECOVERED_ERROR) { MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_IDLE; MSC_Handle->unit[MSC_Handle->current_lun].error = MSC_ERROR; } break; case MSC_REQUEST_SENSE_WAIT_RETRY: if ((HAL_GetTick() - MSC_Handle->retry_timeout) > MSC_STARTUP_RETRY_TIME_MS) { MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY; } break; case MSC_UNRECOVERED_ERROR: MSC_Handle->current_lun++; break; default: break; } } else { MSC_Handle->current_lun = 0; MSC_Handle->state = MSC_IDLE; phost->pUser(phost, HOST_USER_CLASS_ACTIVE); } break; case MSC_IDLE: error = USBH_OK; break; #ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED case MSC_WRITE: #endif case MSC_READ: error = USBH_MSC_RdWrProcess(phost, MSC_Handle->rw_lun); if(((int32_t)(phost->Timer - MSC_Handle->timeout) > 0) || (phost->device.is_connected == 0)) { error = USBH_FAIL; } if (error != USBH_BUSY) { MSC_Handle->state = MSC_IDLE; if (MSC_Handle->RdWrCompleteCallback != NULL) { MSC_Handle->RdWrCompleteCallback(error); MSC_Handle->RdWrCompleteCallback = NULL; } } break; default: break; } return error; } /** * @brief USBH_MSC_SOFProcess * The function is for SOF state * @param phost: Host handle * @retval USBH Status */ static USBH_StatusTypeDef USBH_MSC_SOFProcess(USBH_HandleTypeDef *phost) { return USBH_OK; } /** * @brief USBH_MSC_RdWrProcess * The function is for managing state machine for MSC I/O Process * @param phost: Host handle * @param lun: logical Unit Number * @retval USBH Status */ static USBH_StatusTypeDef USBH_MSC_RdWrProcess(USBH_HandleTypeDef *phost, uint8_t lun) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; USBH_StatusTypeDef error = USBH_BUSY ; USBH_StatusTypeDef scsi_status = USBH_BUSY ; /* Switch MSC REQ state machine */ switch (MSC_Handle->unit[lun].state) { case MSC_READ: scsi_status = USBH_MSC_SCSI_Read(phost,lun, 0, 0) ; if(scsi_status == USBH_OK) { MSC_Handle->unit[lun].state = MSC_IDLE; error = USBH_OK; } else if( scsi_status == USBH_FAIL) { MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE; } else if(scsi_status == USBH_UNRECOVERED_ERROR) { MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR; error = USBH_FAIL; } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); #endif break; #ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED case MSC_WRITE: scsi_status = USBH_MSC_SCSI_Write(phost,lun, 0, 0) ; if(scsi_status == USBH_OK) { MSC_Handle->unit[lun].state = MSC_IDLE; error = USBH_OK; } else if( scsi_status == USBH_FAIL) { MSC_Handle->unit[lun].state = MSC_REQUEST_SENSE; } else if(scsi_status == USBH_UNRECOVERED_ERROR) { MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR; error = USBH_FAIL; } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); #endif break; #endif //#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED case MSC_REQUEST_SENSE: scsi_status = USBH_MSC_SCSI_RequestSense(phost, lun, &MSC_Handle->unit[lun].sense); if( scsi_status == USBH_OK) { USBH_UsrLog ("Sense Key : %x", MSC_Handle->unit[lun].sense.key); USBH_UsrLog ("Additional Sense Code : %x", MSC_Handle->unit[lun].sense.asc); USBH_UsrLog ("Additional Sense Code Qualifier: %x", MSC_Handle->unit[lun].sense.ascq); MSC_Handle->unit[lun].state = MSC_IDLE; MSC_Handle->unit[lun].error = MSC_ERROR; error = USBH_FAIL; } if( scsi_status == USBH_FAIL) { USBH_UsrLog ("MSC Device NOT ready"); } else if(scsi_status == USBH_UNRECOVERED_ERROR) { MSC_Handle->unit[lun].state = MSC_UNRECOVERED_ERROR; error = USBH_FAIL; } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_CLASS_EVENT, 0); #endif break; default: break; } return error; } /** * @brief USBH_MSC_IsReady * The function check if the MSC function is ready * @param phost: Host handle * @retval USBH Status */ uint8_t USBH_MSC_IsReady (USBH_HandleTypeDef *phost) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if(phost->gState == HOST_CLASS) { return (MSC_Handle->state == MSC_IDLE); } else { return 0; } } /** * @brief USBH_MSC_GetMaxLUN * The function return the Max LUN supported * @param phost: Host handle * @retval logical Unit Number supported */ int8_t USBH_MSC_GetMaxLUN (USBH_HandleTypeDef *phost) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if ((phost->gState == HOST_CLASS) && (MSC_Handle->state == MSC_IDLE)) { return MSC_Handle->max_lun; } return 0xFF; } /** * @brief USBH_MSC_UnitIsReady * The function check whether a LUN is ready * @param phost: Host handle * @param lun: logical Unit Number * @retval Lun status (0: not ready / 1: ready) */ uint8_t USBH_MSC_UnitIsReady (USBH_HandleTypeDef *phost, uint8_t lun) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if(phost->gState == HOST_CLASS) { return (MSC_Handle->unit[lun].error == MSC_OK); } else { return 0; } } /** * @brief USBH_MSC_GetLUNInfo * The function return a LUN information * @param phost: Host handle * @param lun: logical Unit Number * @retval USBH Status */ USBH_StatusTypeDef USBH_MSC_GetLUNInfo(USBH_HandleTypeDef *phost, uint8_t lun, MSC_LUNTypeDef *info) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if(phost->gState == HOST_CLASS) { USBH_memcpy(info,&MSC_Handle->unit[lun], sizeof(MSC_LUNTypeDef)); return USBH_OK; } else { return USBH_FAIL; } } /** * @brief USBH_MSC_Read * The function performs a Read operation * @param phost: Host handle * @param lun: logical Unit Number * @param address: sector address * @param pbuf: pointer to data * @param length: number of sector to read * @retval USBH Status */ USBH_StatusTypeDef USBH_MSC_Read(USBH_HandleTypeDef *phost, uint8_t lun, uint32_t address, uint32_t length, MSC_RdWrCompleteCallback callback) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if ((phost->device.is_connected == 0) || (phost->gState != HOST_CLASS) || (MSC_Handle->state != MSC_IDLE) || (MSC_Handle->unit[lun].state != MSC_IDLE)) { return USBH_FAIL; } MSC_Handle->state = MSC_READ; MSC_Handle->unit[lun].state = MSC_READ; MSC_Handle->rw_lun = lun; MSC_Handle->RdWrCompleteCallback = callback; MSC_Handle->timeout = HAL_GetTick() + MSC_TIMEOUT_FIXED_MS; USBH_MSC_SCSI_Read(phost, lun, address, length); return USBH_OK; } /** * @brief USBH_MSC_Write * The function performs a Write operation * @param phost: Host handle * @param lun: logical Unit Number * @param address: sector address * @param pbuf: pointer to data * @param length: number of sector to write * @retval USBH Status */ #ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost, uint8_t lun, uint32_t address, uint32_t length, MSC_RdWrCompleteCallback callback) { MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if ((phost->device.is_connected == 0) || (phost->gState != HOST_CLASS) || (MSC_Handle->state != MSC_IDLE) || (MSC_Handle->unit[lun].state != MSC_IDLE)) { return USBH_FAIL; } MSC_Handle->state = MSC_WRITE; MSC_Handle->unit[lun].state = MSC_WRITE; MSC_Handle->rw_lun = lun; MSC_Handle->RdWrCompleteCallback = callback; MSC_Handle->timeout = HAL_GetTick() + MSC_TIMEOUT_FIXED_MS; USBH_MSC_SCSI_Write(phost, lun, address, length); return USBH_OK; } #endif //#ifdef CONFIG_MASS_STORAGE_WRITES_PERMITTED #endif //#ifdef CONFIG_MASS_STORAGE_ENABLED /** * @} */ /** * @} */ /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/