/** ****************************************************************************** * @file usbh_msc.c * @author MCD Application Team * @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 (c) 2015 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* BSPDependencies - "stm32xxxxx_{eval}{discovery}{nucleo_144}.c" - "stm32xxxxx_{eval}{discovery}_io.c" - "stm32xxxxx_{eval}{discovery}{adafruit}_lcd.c" - "stm32xxxxx_{eval}{discovery}_sdram.c" EndBSPDependencies */ /* Includes ------------------------------------------------------------------*/ #include "usbh_msc.h" #include "usbh_msc_bot.h" #include "usbh_msc_scsi.h" /** @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) { USBH_StatusTypeDef status; uint8_t interface; MSC_HandleTypeDef *MSC_Handle; interface = USBH_FindInterface(phost, phost->pActiveClass->ClassCode, MSC_TRANSPARENT, MSC_BOT); if ((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES)) /* Not Valid Interface */ { USBH_DbgLog("Cannot Find the interface for %s class.", phost->pActiveClass->Name); return USBH_FAIL; } status = USBH_SelectInterface(phost, interface); if (status != USBH_OK) { return USBH_FAIL; } phost->pActiveClass->pData = (MSC_HandleTypeDef *)USBH_malloc(sizeof(MSC_HandleTypeDef)); MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if (MSC_Handle == NULL) { USBH_DbgLog("Cannot allocate memory for MSC Handle"); return USBH_FAIL; } /* Initialize msc handler */ USBH_memset(MSC_Handle, 0, sizeof(MSC_HandleTypeDef)); if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U) { MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress); MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; } else { MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress); MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize; } if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress & 0x80U) { MSC_Handle->InEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress); MSC_Handle->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize; } else { MSC_Handle->OutEp = (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].bEndpointAddress); MSC_Handle->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[1].wMaxPacketSize; } 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); USBH_MSC_BOT_Init(phost); /* 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, 0U); USBH_LL_SetToggle(phost, MSC_Handle->OutPipe, 0U); return USBH_OK; } /** * @brief USBH_MSC_InterfaceDeInit * The function DeInit the Pipes used for the MSC class. * @param phost: Host handle * @retval USBH Status */ static 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 = 0U; /* Reset the Channel as Free */ } if (MSC_Handle->InPipe) { USBH_ClosePipe(phost, MSC_Handle->InPipe); USBH_FreePipe(phost, MSC_Handle->InPipe); MSC_Handle->InPipe = 0U; /* Reset the Channel as Free */ } if (phost->pActiveClass->pData) { USBH_free(phost->pActiveClass->pData); phost->pActiveClass->pData = 0U; } 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; uint8_t i; /* Switch MSC REQ state machine */ switch (MSC_Handle->req_state) { case MSC_REQ_IDLE: case MSC_REQ_GET_MAX_LUN: /* Issue GetMaxLUN request */ status = USBH_MSC_BOT_REQ_GetMaxLUN(phost, &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 = 0U; status = USBH_OK; } if (status == USBH_OK) { MSC_Handle->max_lun = (MSC_Handle->max_lun > MAX_SUPPORTED_LUN) ? MAX_SUPPORTED_LUN : (MSC_Handle->max_lun + 1U); USBH_UsrLog("Number of supported LUN: %d", MSC_Handle->max_lun); for (i = 0U; i < MSC_Handle->max_lun; i++) { MSC_Handle->unit[i].prev_ready_state = USBH_FAIL; MSC_Handle->unit[i].state_changed = 0U; } } break; case MSC_REQ_ERROR: /* a Clear Feature should be issued here */ if (USBH_ClrFeature(phost, 0x00U) == 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->timer = phost->Timer; break; case MSC_READ_INQUIRY: scsi_status = USBH_MSC_SCSI_Inquiry(phost, (uint8_t)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, (uint8_t)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 = 1U; USBH_UsrLog("MSC Device ready"); } else { MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0U; } 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 = 1U; USBH_UsrLog("MSC Device NOT ready"); } else { MSC_Handle->unit[MSC_Handle->current_lun].state_changed = 0U; } 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, (uint8_t)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 == 1U) { 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, (uint8_t)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 ((phost->Timer - MSC_Handle->timer) < 10000U) { MSC_Handle->unit[MSC_Handle->current_lun].state = MSC_TEST_UNIT_READY; 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_UNRECOVERED_ERROR: MSC_Handle->current_lun++; break; default: break; } #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_CLASS_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif } else { MSC_Handle->current_lun = 0U; MSC_Handle->state = MSC_IDLE; #if (USBH_USE_OS == 1U) phost->os_msg = (uint32_t)USBH_CLASS_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif phost->pUser(phost, HOST_USER_CLASS_ACTIVE); } break; case MSC_IDLE: error = USBH_OK; 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) { /* Prevent unused argument(s) compilation warning */ UNUSED(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, 0U, NULL, 0U); 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 == 1U) phost->os_msg = (uint32_t)USBH_CLASS_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; case MSC_WRITE: scsi_status = USBH_MSC_SCSI_Write(phost, lun, 0U, NULL, 0U); 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 == 1U) phost->os_msg = (uint32_t)USBH_CLASS_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #endif break; 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 == 1U) phost->os_msg = (uint32_t)USBH_CLASS_EVENT; #if (osCMSIS < 0x20000U) (void)osMessagePut(phost->os_event, phost->os_msg, 0U); #else (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL); #endif #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; uint8_t res; if ((phost->gState == HOST_CLASS) && (MSC_Handle->state == MSC_IDLE)) { res = 1U; } else { res = 0U; } return res; } /** * @brief USBH_MSC_GetMaxLUN * The function return the Max LUN supported * @param phost: Host handle * @retval logical Unit Number supported */ uint8_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 (uint8_t)MSC_Handle->max_lun; } return 0xFFU; } /** * @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; uint8_t res; if ((phost->gState == HOST_CLASS) && (MSC_Handle->unit[lun].error == MSC_OK)) { res = 1U; } else { res = 0U; } return res; } /** * @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, uint8_t *pbuf, uint32_t length) { uint32_t timeout; MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if ((phost->device.is_connected == 0U) || (phost->gState != HOST_CLASS) || (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; USBH_MSC_SCSI_Read(phost, lun, address, pbuf, length); timeout = phost->Timer; while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY) { if (((phost->Timer - timeout) > (10000U * length)) || (phost->device.is_connected == 0U)) { MSC_Handle->state = MSC_IDLE; return USBH_FAIL; } } MSC_Handle->state = MSC_IDLE; 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 */ USBH_StatusTypeDef USBH_MSC_Write(USBH_HandleTypeDef *phost, uint8_t lun, uint32_t address, uint8_t *pbuf, uint32_t length) { uint32_t timeout; MSC_HandleTypeDef *MSC_Handle = (MSC_HandleTypeDef *) phost->pActiveClass->pData; if ((phost->device.is_connected == 0U) || (phost->gState != HOST_CLASS) || (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; USBH_MSC_SCSI_Write(phost, lun, address, pbuf, length); timeout = phost->Timer; while (USBH_MSC_RdWrProcess(phost, lun) == USBH_BUSY) { if (((phost->Timer - timeout) > (10000U * length)) || (phost->device.is_connected == 0U)) { MSC_Handle->state = MSC_IDLE; return USBH_FAIL; } } MSC_Handle->state = MSC_IDLE; return USBH_OK; } /** * @} */ /** * @} */ /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/