/* * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. * Copyright 2016 - 2017,2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "usb_device_config.h" #include "usb.h" #include "usb_device.h" #include "usb_device_class.h" #if ((defined(USB_DEVICE_CONFIG_MSC)) && (USB_DEVICE_CONFIG_MSC > 0U)) #include "usb_device_msc.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ usb_status_t USB_DeviceMscRecv(usb_device_msc_struct_t *mscHandle); usb_status_t USB_DeviceMscSend(usb_device_msc_struct_t *mscHandle); usb_status_t USB_DeviceMscEndpointsInit(usb_device_msc_struct_t *mscHandle); usb_status_t USB_DeviceMscEndpointsDeinit(usb_device_msc_struct_t *mscHandle); /******************************************************************************* * Variables ******************************************************************************/ #if (USB_DEVICE_CONFIG_MSC == 1U) USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_cbw_t s_MscCbw1; #define MSCCBW_ARRAY \ { \ &s_MscCbw1 \ } USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_csw_t s_MscCsw1; #define MSCCSW_ARRAY \ { \ &s_MscCsw1 \ } USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_request_sense_data_struct_t requestSense1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity_struct_t readCapacity1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity16_data_struct_t readCapacity161; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t formatCapacityData1[sizeof(usb_device_capacity_list_header_struct_t) + sizeof(usb_device_current_max_capacity_descriptor_struct_t) + sizeof(usb_device_formattable_capacity_descriptor_struct_t) * 3]; #define MSCSENSE_ARRAY \ { \ &requestSense1 \ } #define MSCCPAP_ARRAY \ { \ &readCapacity1 \ } #define MSCCAPA16_ARRAY \ { \ &readCapacity161 \ } #define MSCFORMAT_ARRAY \ { \ &formatCapacityData1[0] \ } #elif (USB_DEVICE_CONFIG_MSC == 2U) USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_cbw_t s_MscCbw1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_cbw_t s_MscCbw2; #define MSCCBW_ARRAY \ { \ &s_MscCbw1, &s_MscCbw2 \ } USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_csw_t s_MscCsw1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_csw_t s_MscCsw2; #define MSCCSW_ARRAY \ { \ &s_MscCsw1, &s_MscCsw2 \ } USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_request_sense_data_struct_t requestSense1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity_struct_t readCapacity1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity16_data_struct_t readCapacity161; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t formatCapacityData1[sizeof(usb_device_capacity_list_header_struct_t) + sizeof(usb_device_current_max_capacity_descriptor_struct_t) + sizeof(usb_device_formattable_capacity_descriptor_struct_t) * 3]; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) usb_device_request_sense_data_struct_t requestSense2; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) usb_device_read_capacity_struct_t readCapacity2; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) usb_device_read_capacity16_data_struct_t readCapacity162; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) uint8_t formatCapacityData2[sizeof(usb_device_capacity_list_header_struct_t) + sizeof(usb_device_current_max_capacity_descriptor_struct_t) + sizeof(usb_device_formattable_capacity_descriptor_struct_t) * 3]; #define MSCSENSE_ARRAY \ { \ &requestSense1, &requestSense2 \ } #define MSCCPAP_ARRAY \ { \ &readCapacity1, &readCapacity2 \ } #define MSCCAPA16_ARRAY \ { \ &readCapacity161, &readCapacity162 \ } #define MSCFORMAT_ARRAY \ { \ &formatCapacityData1[0], &formatCapacityData2[0] \ } #elif (USB_DEVICE_CONFIG_MSC == 3U) USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_cbw_t s_MscCbw1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_cbw_t s_MscCbw2; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_cbw_t s_MscCbw3; #define MSCCBW_ARRAY \ { \ &s_MscCbw1, &s_MscCbw2, &s_MscCbw3 \ } USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_csw_t s_MscCsw1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_csw_t s_MscCsw2; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_csw_t s_MscCsw3; #define MSCCSW_ARRAY \ { \ &s_MscCsw1, &s_MscCsw2, &s_MscCsw3 \ } USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_request_sense_data_struct_t requestSense1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity_struct_t readCapacity1; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity16_data_struct_t readCapacity161; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t formatCapacityData1[sizeof(usb_device_capacity_list_header_struct_t) + sizeof(usb_device_current_max_capacity_descriptor_struct_t) + sizeof(usb_device_formattable_capacity_descriptor_struct_t) * 3]; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_request_sense_data_struct_t requestSense2; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity_struct_t readCapacity2; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity16_data_struct_t readCapacity162; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t formatCapacityData2[sizeof(usb_device_capacity_list_header_struct_t) + sizeof(usb_device_current_max_capacity_descriptor_struct_t) + sizeof(usb_device_formattable_capacity_descriptor_struct_t) * 3]; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_request_sense_data_struct_t requestSense3; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity_struct_t readCapacity3; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_read_capacity16_data_struct_t readCapacity163; USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t formatCapacityData3[sizeof(usb_device_capacity_list_header_struct_t) + sizeof(usb_device_current_max_capacity_descriptor_struct_t) + sizeof(usb_device_formattable_capacity_descriptor_struct_t) * 3]; #define MSCSENSE_ARRAY \ { \ &requestSense1, &requestSense2, &requestSense3 \ } #define MSCCPAP_ARRAY \ { \ &readCapacity1, &readCapacity2, &readCapacity3 \ } #define MSCCAPA16_ARRAY \ { \ &readCapacity161, &readCapacity162, &readCapacity163 \ } #define MSCFORMAT_ARRAY \ { \ &formatCapacityData1[0], &formatCapacityData2[0], &formatCapacityData3[0] \ } #else #error "the max support USB_DEVICE_CONFIG_MSC is 3" #endif USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_msc_struct_t g_msc_handle[USB_DEVICE_CONFIG_MSC]; /******************************************************************************* * Code ******************************************************************************/ /*! * @brief Allocate a device msc class handle. * * This function allocates a device msc class handle. * * @param handle It is out parameter, is used to return pointer of the device msc class handle to the caller. * * @retval kStatus_USB_Success Get a device msc class handle successfully. * @retval kStatus_USB_Busy Cannot allocate a device msc class handle. */ static usb_status_t USB_DeviceMscAllocateHandle(usb_device_msc_struct_t **handle) { uint32_t count; usb_device_msc_cbw_t *cbw_array[] = MSCCBW_ARRAY; usb_device_msc_csw_t *csw_array[] = MSCCSW_ARRAY; usb_device_request_sense_data_struct_t *sense[] = MSCSENSE_ARRAY; usb_device_read_capacity_struct_t *capacity_array[] = MSCCPAP_ARRAY; usb_device_read_capacity16_data_struct_t *capacity16_array[] = MSCCAPA16_ARRAY; uint8_t *formatCapacityData[] = MSCFORMAT_ARRAY; for (count = 0; count < USB_DEVICE_CONFIG_MSC; count++) { if (NULL == g_msc_handle[count].handle) { g_msc_handle[count].mscCbw = (cbw_array[count]); g_msc_handle[count].mscCsw = (csw_array[count]); g_msc_handle[count].mscUfi.requestSense = (sense[count]); g_msc_handle[count].mscUfi.readCapacity = (capacity_array[count]); g_msc_handle[count].mscUfi.readCapacity16 = (capacity16_array[count]); g_msc_handle[count].mscUfi.formatCapacityData = (formatCapacityData[count]); *handle = &g_msc_handle[count]; return kStatus_USB_Success; } } return kStatus_USB_Busy; } /*! * @brief Free a device msc class handle. * * This function frees a device msc class handle. * * @param handle The device msc class handle. * * @retval kStatus_USB_Success Free device msc class handle successfully. */ static usb_status_t USB_DeviceMscFreeHandle(usb_device_msc_struct_t *handle) { handle->handle = NULL; handle->configurationStruct = (usb_device_class_config_struct_t *)NULL; handle->configuration = 0; handle->alternate = 0; return kStatus_USB_Success; } /*! * @brief Process usb msc ufi command. * * This function analyse the cbw , get the command code. * * @param handle The device msc class handle. * * @retval kStatus_USB_Success Free device msc class handle successfully. */ static usb_status_t USB_DeviceMscProcessUfiCommand(usb_device_msc_struct_t *mscHandle) { usb_status_t status; usb_device_msc_ufi_struct_t *ufi = NULL; ufi = &mscHandle->mscUfi; if (USB_DEVICE_MSC_REQUEST_SENSE_COMMAND != mscHandle->mscCbw->cbwcb[0]) { ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_NO_SENSE; ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_NO_SENSE; ufi->requestSense->additionalSenseQualifer = USB_DEVICE_MSC_UFI_NO_SENSE; } ufi->thirteenCase.hostExpectedDataLength = mscHandle->mscCbw->dataTransferLength; ufi->thirteenCase.hostExpectedDirection = (uint8_t)(mscHandle->mscCbw->flags >> USB_DEVICE_MSC_CBW_DIRECTION_SHIFT); /*The first byte of all ufi command blocks shall contain an Operation Code, refer to ufi spec*/ switch (mscHandle->mscCbw->cbwcb[0]) { /* ufi command operation code*/ case USB_DEVICE_MSC_INQUIRY_COMMAND: /*operation code : 0x12*/ status = USB_DeviceMscUfiInquiryCommand(mscHandle); break; case USB_DEVICE_MSC_READ_10_COMMAND: /*operation code : 0x28 */ case USB_DEVICE_MSC_READ_12_COMMAND: /*operation code : 0xA8 */ status = USB_DeviceMscUfiReadCommand(mscHandle); break; case USB_DEVICE_MSC_REQUEST_SENSE_COMMAND: /*operation code : 0x03*/ status = USB_DeviceMscUfiRequestSenseCommand(mscHandle); break; case USB_DEVICE_MSC_TEST_UNIT_READY_COMMAND: /*operation code : 0x00 */ status = USB_DeviceMscUfiTestUnitReadyCommand(mscHandle); break; case USB_DEVICE_MSC_WRITE_10_COMMAND: /*operation code : 0x2A */ case USB_DEVICE_MSC_WRITE_12_COMMAND: /*operation code : 0xAA */ status = USB_DeviceMscUfiWriteCommand(mscHandle); break; case USB_DEVICE_MSC_PREVENT_ALLOW_MEDIUM_REM_COMMAND: /*operation code :0x1E */ status = USB_DeviceMscUfiPreventAllowMediumCommand(mscHandle); break; case USB_DEVICE_MSC_FORMAT_UNIT_COMMAND: /*operation code : 0x04*/ status = USB_DeviceMscUfiFormatUnitCommand(mscHandle); break; case USB_DEVICE_MSC_READ_CAPACITY_10_COMMAND: /*operation code : 0x25*/ case USB_DEVICE_MSC_READ_CAPACITY_16_COMMAND: /*operation code : 0x9E*/ status = USB_DeviceMscUfiReadCapacityCommand(mscHandle); break; case USB_DEVICE_MSC_MODE_SENSE_10_COMMAND: /* operation code :0x5A*/ case USB_DEVICE_MSC_MODE_SENSE_6_COMMAND: /* operation code : 0x1A */ status = USB_DeviceMscUfiModeSenseCommand(mscHandle); break; case USB_DEVICE_MSC_MODE_SELECT_10_COMMAND: /*operation code : 0x55 */ case USB_DEVICE_MSC_MODE_SELECT_6_COMMAND: /*operation code : 0x15 */ status = USB_DeviceMscUfiModeSelectCommand(mscHandle); break; case USB_DEVICE_MSC_READ_FORMAT_CAPACITIES_COMMAND: /*operation code : 0x23 */ status = USB_DeviceMscUfiReadFormatCapacityCommand(mscHandle); break; case USB_DEVICE_MSC_SEND_DIAGNOSTIC_COMMAND: /*operation code : 0x1D*/ status = USB_DeviceMscUfiSendDiagnosticCommand(mscHandle); break; case USB_DEVICE_MSC_VERIFY_COMMAND: /*operation code : 0x2F*/ status = USB_DeviceMscUfiVerifyCommand(mscHandle); break; case USB_DEVICE_MSC_START_STOP_UNIT_COMMAND: /*operation code : 0x1B*/ status = USB_DeviceMscUfiStartStopUnitCommand(mscHandle); break; default: status = USB_DeviceMscUfiUnsupportCommand(mscHandle); break; } if ((USB_DEVICE_MSC_UFI_NO_SENSE != ufi->requestSense->senseKey) && (USB_DEVICE_MSC_COMMAND_PASSED == mscHandle->mscCsw->cswStatus) && (USB_DEVICE_MSC_REQUEST_SENSE_COMMAND != mscHandle->mscCbw->cbwcb[0])) { mscHandle->mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED; } return status; } /*! * @brief Bulk IN endpoint callback function. * * This callback function is used to notify upper layer the transfer result of a transfer. * This callback pointer is passed when the Bulk IN pipe initialized. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param message The result of the Bulk IN pipe transfer. * @param callbackParam The parameter for this callback. It is same with * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the MSC class handle. * * @return A USB error code or kStatus_USB_Success. */ static usb_status_t USB_DeviceMscBulkIn(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam) { usb_device_msc_struct_t *mscHandle = (usb_device_msc_struct_t *)callbackParam; usb_device_msc_csw_t *csw = NULL; void *temp; usb_status_t error = kStatus_USB_Error; /* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */ if (message->length == USB_CANCELLED_TRANSFER_LENGTH) { /*this code is called when stack cancel the transfer, app should release the buffer it use */ if ((0U != mscHandle->dataInFlag) && (mscHandle->configurationStruct->classCallback != NULL) && ((USB_DEVICE_MSC_READ_10_COMMAND == mscHandle->mscCbw->cbwcb[0]) || (USB_DEVICE_MSC_READ_12_COMMAND == mscHandle->mscCbw->cbwcb[0]))) { usb_device_lba_app_struct_t lbaData; lbaData.size = 0; lbaData.buffer = message->buffer; lbaData.offset = 0; lbaData.lun = mscHandle->mscCbw->logicalUnitNumber; /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit */ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventReadResponse, (void *)&lbaData)) { return kStatus_USB_Error; } #else (void)mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventReadResponse, (void *)&lbaData); #endif } if (mscHandle->inEndpointCswCancelFlag == 1U) { mscHandle->inEndpointCswCancelFlag = 0U; /*cancel the transfer and wait for the calcel to be complete in bulk in callback*/ /*send csw*/ mscHandle->mscCsw->dataResidue = USB_LONG_TO_LITTLE_ENDIAN(mscHandle->mscCsw->dataResidue); #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH); #endif mscHandle->cswPrimeFlag = 1; mscHandle->stallStatus = 0; } return error; } if (mscHandle->transferRemaining >= message->length) { mscHandle->transferRemaining -= message->length; } if (mscHandle->needInStallFlag == 1U) { mscHandle->needInStallFlag = 0U; mscHandle->inEndpointStallFlag = 1U; mscHandle->dataInFlag = 0U; #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkInEndpoint)) { return kStatus_USB_Error; } #else (void)USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkInEndpoint); #endif return error; } if ((0U == mscHandle->dataInFlag) && (message->length == USB_DEVICE_MSC_CSW_LENGTH)) { temp = (void *)(message->buffer); csw = (usb_device_msc_csw_t *)temp; } if (0U != mscHandle->dataInFlag) { if ((mscHandle->configurationStruct->classCallback != NULL)) { usb_device_lba_app_struct_t lbaData; lbaData.size = message->length; lbaData.buffer = message->buffer; lbaData.offset = mscHandle->currentOffset; lbaData.lun = mscHandle->mscCbw->logicalUnitNumber; if ((USB_DEVICE_MSC_READ_10_COMMAND == mscHandle->mscCbw->cbwcb[0]) || (USB_DEVICE_MSC_READ_12_COMMAND == mscHandle->mscCbw->cbwcb[0])) { /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit */ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventReadResponse, (void *)&lbaData)) { return kStatus_USB_Error; } #else (void)mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventReadResponse, (void *)&lbaData); #endif } if (0U != mscHandle->transferRemaining) { mscHandle->currentOffset += (message->length / mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].lengthOfEachLba); error = USB_DeviceMscSend(mscHandle); } if (0U == mscHandle->transferRemaining) { mscHandle->dataInFlag = 0U; /*data transfer has been done, send the csw to host */ mscHandle->cswPrimeFlag = 1U; mscHandle->mscCsw->dataResidue = USB_LONG_TO_LITTLE_ENDIAN(mscHandle->mscCsw->dataResidue); #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH); #endif } } } else if ((message->length == USB_DEVICE_MSC_CSW_LENGTH) && (USB_DEVICE_MSC_DCSWSIGNATURE == csw->signature)) { mscHandle->cbwValidFlag = 1U; mscHandle->cswPrimeFlag = 0U; #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH); #endif mscHandle->cbwPrimeFlag = 1U; } else { /*no action*/ } return error; } /*! * @brief Bulk OUT endpoint callback function. * * This callback function is used to notify upper layer the transfer result of a transfer. * This callback pointer is passed when the Bulk OUT pipe initialized. * * @param handle The device handle. It equals the value returned from USB_DeviceInit. * @param message The result of the Bulk OUT pipe transfer. * @param callbackParam The parameter for this callback. It is same with * usb_device_endpoint_callback_struct_t::callbackParam. In the class, the value is the MSC class handle. * * @return A USB error code or kStatus_USB_Success. */ static usb_status_t USB_DeviceMscBulkOut(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, void *callbackParam) { usb_device_msc_struct_t *mscHandle = (usb_device_msc_struct_t *)callbackParam; usb_status_t error = kStatus_USB_Success; /* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */ if (message->length == USB_CANCELLED_TRANSFER_LENGTH) { /*this code is called when stack cancel the transfer, app should release the buffer it use*/ if ((0U != mscHandle->dataOutFlag) && (mscHandle->configurationStruct->classCallback != NULL) && ((USB_DEVICE_MSC_WRITE_10_COMMAND == mscHandle->mscCbw->cbwcb[0]) || (USB_DEVICE_MSC_WRITE_12_COMMAND == mscHandle->mscCbw->cbwcb[0]))) { usb_device_lba_app_struct_t lbaData; lbaData.size = 0; lbaData.buffer = message->buffer; lbaData.offset = 0; lbaData.lun = mscHandle->mscCbw->logicalUnitNumber; /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit */ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventWriteResponse, (void *)&lbaData)) { return kStatus_USB_Error; } #else (void)mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventWriteResponse, (void *)&lbaData); #endif } if ((mscHandle->cbwPrimeFlag == 0U) && (mscHandle->inEndpointStallFlag == 0U) && (mscHandle->outEndpointStallFlag == 0U)) { /*prime cbw*/ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH); #endif mscHandle->cbwPrimeFlag = 1U; } return error; } if (mscHandle->transferRemaining >= message->length) { mscHandle->transferRemaining -= message->length; } if ((USB_DEVICE_MSC_MODE_SELECT_10_COMMAND == mscHandle->mscCbw->cbwcb[0]) || (USB_DEVICE_MSC_MODE_SELECT_6_COMMAND == mscHandle->mscCbw->cbwcb[0])) { if ((mscHandle->configurationStruct->classCallback != NULL)) { /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit */ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventModeSelectResponse, (void *)NULL)) { return kStatus_USB_Error; } #else (void)mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventModeSelectResponse, (void *)NULL); #endif } } if (mscHandle->needOutStallFlag == 1U) { mscHandle->needOutStallFlag = 0U; mscHandle->outEndpointStallFlag = 1U; mscHandle->dataOutFlag = 0U; mscHandle->cbwPrimeFlag = 0U; #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkOutEndpoint)) { return kStatus_USB_Error; } #else (void)USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkOutEndpoint); #endif return error; } if (0U != mscHandle->dataOutFlag) { usb_device_lba_app_struct_t lbaData; lbaData.size = message->length; lbaData.buffer = message->buffer; lbaData.offset = mscHandle->currentOffset; lbaData.lun = mscHandle->mscCbw->logicalUnitNumber; if ((mscHandle->configurationStruct->classCallback != NULL)) { if ((USB_DEVICE_MSC_WRITE_10_COMMAND == mscHandle->mscCbw->cbwcb[0]) || (USB_DEVICE_MSC_WRITE_12_COMMAND == mscHandle->mscCbw->cbwcb[0])) { /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit */ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventWriteResponse, (void *)&lbaData)) { return kStatus_USB_Error; } #else (void)mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventWriteResponse, (void *)&lbaData); #endif } if (0U != mscHandle->transferRemaining) { mscHandle->currentOffset += (message->length / mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].lengthOfEachLba); error = USB_DeviceMscRecv(mscHandle); } } if (0U == mscHandle->transferRemaining) { mscHandle->dataOutFlag = 0U; { mscHandle->mscCsw->dataResidue = USB_LONG_TO_LITTLE_ENDIAN(mscHandle->mscCsw->dataResidue); #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH); #endif mscHandle->cswPrimeFlag = 1U; } } } else if ((0U != mscHandle->cbwValidFlag) && (message->length == USB_DEVICE_MSC_CBW_LENGTH) && (USB_DEVICE_MSC_DCBWSIGNATURE == mscHandle->mscCbw->signature) && (!((0U != (mscHandle->mscCbw->logicalUnitNumber & 0xF0U)) || (0U != (mscHandle->mscCbw->cbLength & 0xE0U)))) && (mscHandle->mscCbw->logicalUnitNumber < (mscHandle->logicalUnitNumber + 1U)) && ((mscHandle->mscCbw->cbLength >= 0x01U) && (mscHandle->mscCbw->cbLength <= 0x10U))) { mscHandle->cbwPrimeFlag = 0U; mscHandle->transferRemaining = 0U; mscHandle->mscCsw->signature = USB_DEVICE_MSC_DCSWSIGNATURE; mscHandle->mscCsw->dataResidue = 0U; mscHandle->mscCsw->tag = mscHandle->mscCbw->tag; mscHandle->cbwValidFlag = 0U; mscHandle->mscCbw->dataTransferLength = USB_LONG_FROM_LITTLE_ENDIAN(mscHandle->mscCbw->dataTransferLength); mscHandle->dataOutFlag = (uint8_t)(((0U == (mscHandle->mscCbw->flags & USB_DEVICE_MSC_CBW_DIRECTION_BIT)) && (0U != mscHandle->mscCbw->dataTransferLength)) ? 1U : 0U); mscHandle->dataInFlag = (uint8_t)(((0U != (mscHandle->mscCbw->flags & USB_DEVICE_MSC_CBW_DIRECTION_BIT)) && (0U != mscHandle->mscCbw->dataTransferLength)) ? 1U : 0U); if ((0U != mscHandle->dataInFlag) && (0U != mscHandle->inEndpointStallFlag)) { error = kStatus_USB_Error; return error; } error = USB_DeviceMscProcessUfiCommand(mscHandle); if (error == kStatus_USB_InvalidRequest) { if (mscHandle->dataOutFlag == 1U) { if (mscHandle->outEndpointStallFlag == 0U) { mscHandle->needOutStallFlag = 1U; } mscHandle->dataOutFlag = 0U; } else if (mscHandle->dataInFlag == 1U) { if (mscHandle->inEndpointStallFlag == 0U) { mscHandle->needInStallFlag = 1U; } mscHandle->dataInFlag = 0U; } else { /*no action*/ } mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA; } if (!((0U != mscHandle->dataOutFlag) || ((0U != mscHandle->dataInFlag) || (0U != mscHandle->needInStallFlag)))) { mscHandle->mscCsw->dataResidue = USB_LONG_TO_LITTLE_ENDIAN(mscHandle->mscCsw->dataResidue); #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH); #endif mscHandle->cswPrimeFlag = 1U; } } else { #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if ((kStatus_USB_Success != USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkOutEndpoint)) || (kStatus_USB_Success != USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkInEndpoint))) { return kStatus_USB_Error; } #else (void)USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkOutEndpoint); (void)USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkInEndpoint); #endif mscHandle->cbwPrimeFlag = 0U; mscHandle->cbwValidFlag = 0U; mscHandle->outEndpointStallFlag = 1U; mscHandle->inEndpointStallFlag = 1U; mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_CBW; mscHandle->performResetRecover = 1; } return error; } /*! * @brief Initialize the endpoints of the msc class. * * This callback function is used to initialize the endpoints of the msc class. * * @param mscHandle The device msc class handle. It equals the value returned from * usb_device_class_config_struct_t::classHandle. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceMscEndpointsInit(usb_device_msc_struct_t *mscHandle) { usb_device_interface_list_t *interfaceList; usb_device_interface_struct_t *interface = (usb_device_interface_struct_t *)NULL; usb_status_t error = kStatus_USB_Error; uint32_t count; uint32_t index; /* Check the configuration is valid or not. */ if ((0U == mscHandle->configuration) || (mscHandle->configuration > mscHandle->configurationStruct->classInfomation->configurations)) { return error; } /* Get the interface list of the new configuration. */ /* Check the interface list is valid or not. */ if (NULL == mscHandle->configurationStruct->classInfomation->interfaceList) { return error; } interfaceList = &mscHandle->configurationStruct->classInfomation->interfaceList[mscHandle->configuration - 1U]; /* Find interface by using the alternate setting of the interface. */ for (count = 0; count < interfaceList->count; count++) { if (USB_DEVICE_CONFIG_MSC_CLASS_CODE == interfaceList->interfaces[count].classCode) { for (index = 0; index < interfaceList->interfaces[count].count; index++) { if (interfaceList->interfaces[count].interface[index].alternateSetting == mscHandle->alternate) { interface = &interfaceList->interfaces[count].interface[index]; break; } } mscHandle->interfaceNumber = interfaceList->interfaces[count].interfaceNumber; break; } } if (NULL == interface) { /* Return error if the interface is not found. */ return error; } /* Keep new interface handle. */ mscHandle->interfaceHandle = interface; /* Initialize the endpoints of the new interface. */ for (count = 0; count < interface->endpointList.count; count++) { usb_device_endpoint_init_struct_t epInitStruct; usb_device_endpoint_callback_struct_t epCallback; epInitStruct.zlt = 0U; epInitStruct.interval = interface->endpointList.endpoint[count].interval; epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress; epInitStruct.maxPacketSize = interface->endpointList.endpoint[count].maxPacketSize; epInitStruct.transferType = interface->endpointList.endpoint[count].transferType; if (USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) { mscHandle->bulkInEndpoint = epInitStruct.endpointAddress; epCallback.callbackFn = USB_DeviceMscBulkIn; } else { mscHandle->bulkOutEndpoint = epInitStruct.endpointAddress; epCallback.callbackFn = USB_DeviceMscBulkOut; } epCallback.callbackParam = mscHandle; error = USB_DeviceInitEndpoint(mscHandle->handle, &epInitStruct, &epCallback); } mscHandle->dataOutFlag = 0U; mscHandle->dataInFlag = 0U; mscHandle->outEndpointStallFlag = 0U; mscHandle->inEndpointStallFlag = 0U; mscHandle->needOutStallFlag = 0U; mscHandle->needInStallFlag = 0U; mscHandle->cbwValidFlag = 1U; mscHandle->transferRemaining = 0U; mscHandle->performResetRecover = 0U; mscHandle->performResetDoneFlag = 0U; mscHandle->stallStatus = 0U; mscHandle->inEndpointCswCancelFlag = 0U; return error; } /*! * @brief De-initialize the endpoints of the msc class. * * This callback function is used to de-initialize the endpoints of the msc class. * * @param mscHandle The device msc class handle. It equals the value returned from * usb_device_class_config_struct_t::classHandle. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceMscEndpointsDeinit(usb_device_msc_struct_t *mscHandle) { usb_status_t status = kStatus_USB_Error; uint32_t count; if (NULL == mscHandle->interfaceHandle) { return status; } /* De-initialize all endpoints of the interface */ for (count = 0; count < mscHandle->interfaceHandle->endpointList.count; count++) { status = USB_DeviceDeinitEndpoint(mscHandle->handle, mscHandle->interfaceHandle->endpointList.endpoint[count].endpointAddress); } mscHandle->interfaceHandle = NULL; return status; } /*! * @brief Initialize the msc class. * * This function is used to initialize the msc class. * * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. * @param config The class configuration information. * @param handle It is out parameter, is used to return pointer of the msc class handle to the caller. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceMscInit(uint8_t controllerId, usb_device_class_config_struct_t *config, class_handle_t *handle) { usb_device_msc_struct_t *mscHandle; usb_status_t error; uint32_t implementingDiskDrive = USB_DEVICE_CONFIG_MSC_IMPLEMENTING_DISK_DRIVE; usb_device_msc_ufi_struct_t *ufi = NULL; /* Allocate a msc class handle. */ error = USB_DeviceMscAllocateHandle(&mscHandle); if (kStatus_USB_Success != error) { return error; } /* Get the device handle according to the controller id. */ error = USB_DeviceClassGetDeviceHandle(controllerId, &mscHandle->handle); if (kStatus_USB_Success != error) { #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceMscFreeHandle(mscHandle)) { return kStatus_USB_Error; } #else (void)USB_DeviceMscFreeHandle(mscHandle); #endif return error; } if (NULL == mscHandle->handle) { #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceMscFreeHandle(mscHandle)) { return kStatus_USB_Error; } #else (void)USB_DeviceMscFreeHandle(mscHandle); #endif return kStatus_USB_InvalidHandle; } /* Save the configuration of the class. */ mscHandle->configurationStruct = config; /* Clear the configuration value. */ mscHandle->configuration = 0U; mscHandle->alternate = 0xffU; ufi = &mscHandle->mscUfi; mscHandle->implementingDiskDrive = implementingDiskDrive; ufi->requestSense->validErrorCode = USB_DEVICE_MSC_UFI_REQ_SENSE_VALID_ERROR_CODE; ufi->requestSense->additionalSenseLength = USB_DEVICE_MSC_UFI_REQ_SENSE_ADDITIONAL_SENSE_LEN; ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_NO_SENSE; ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_NO_SENSE; ufi->requestSense->additionalSenseQualifer = USB_DEVICE_MSC_UFI_NO_SENSE; mscHandle->cbwPrimeFlag = 0U; mscHandle->cswPrimeFlag = 0U; *handle = (class_handle_t)mscHandle; return error; } /*! * @brief De-initialize the device msc class. * * The function de-initializes the device msc class. * * @param handle The msc class handle got from usb_device_class_config_struct_t::classHandle. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceMscDeinit(class_handle_t handle) { usb_device_msc_struct_t *mscHandle; usb_status_t status = kStatus_USB_Error; mscHandle = (usb_device_msc_struct_t *)handle; if (NULL == mscHandle) { return kStatus_USB_InvalidHandle; } status = USB_DeviceMscEndpointsDeinit(mscHandle); #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceMscFreeHandle(mscHandle)) { return kStatus_USB_Error; } #else (void)USB_DeviceMscFreeHandle(mscHandle); #endif return status; } /*! * @brief Handle the event passed to the msc class. * * This function handles the event passed to the msc class. * * @param handle The msc class handle, got from the usb_device_class_config_struct_t::classHandle. * @param event The event codes. Please refer to the enumeration usb_device_class_event_t. * @param param The param type is determined by the event code. * * @return A USB error code or kStatus_USB_Success. * @retval kStatus_USB_Success Free device handle successfully. * @retval kStatus_USB_InvalidParameter The device handle not be found. * @retval kStatus_USB_InvalidRequest The request is invalid, and the control pipe will be stalled by the caller. */ usb_status_t USB_DeviceMscEvent(void *handle, uint32_t event, void *param) { usb_status_t error = kStatus_USB_Error; usb_device_msc_ufi_struct_t *ufi = NULL; usb_device_msc_struct_t *mscHandle; usb_device_lba_information_struct_t diskInformation; uint16_t interfaceAlternate; uint8_t *temp8; uint8_t alternate; uint8_t index; usb_device_class_event_t eventCode = (usb_device_class_event_t)event; if ((NULL == param) || (NULL == handle)) { return kStatus_USB_InvalidHandle; } /* Get the msc class handle. */ mscHandle = (usb_device_msc_struct_t *)handle; switch (eventCode) { case kUSB_DeviceClassEventDeviceReset: /* Bus reset, clear the configuration. */ mscHandle->configuration = 0U; /* Get device information. classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit */ error = mscHandle->configurationStruct->classCallback( (class_handle_t)mscHandle, kUSB_DeviceMscEventGetLbaInformation, (void *)&diskInformation); if (0U >= diskInformation.logicalUnitNumberSupported) { diskInformation.logicalUnitNumberSupported = 0U; } else { mscHandle->logicalUnitNumber = (uint8_t)diskInformation.logicalUnitNumberSupported - 1U; } /*add for misra2.2*/ if (0U == diskInformation.logicalUnitNumberSupported) { error = kStatus_USB_InvalidParameter; break; } /*initialize the basic device information*/ for (index = 0U; (index <= mscHandle->logicalUnitNumber) && (index < USB_DEVICE_MSC_MAX_LUN); ++index) { if (((0U == diskInformation.logicalUnitInformations[index].lengthOfEachLba) || (0U == diskInformation.logicalUnitInformations[index].totalLbaNumberSupports))) { error = kStatus_USB_Error; } else { mscHandle->luInformations[index] = diskInformation.logicalUnitInformations[index]; } } ufi = &mscHandle->mscUfi; ufi->requestSense->validErrorCode = USB_DEVICE_MSC_UFI_REQ_SENSE_VALID_ERROR_CODE; ufi->requestSense->additionalSenseLength = USB_DEVICE_MSC_UFI_REQ_SENSE_ADDITIONAL_SENSE_LEN; ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_NO_SENSE; ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_NO_SENSE; ufi->requestSense->additionalSenseQualifer = USB_DEVICE_MSC_UFI_NO_SENSE; mscHandle->cbwPrimeFlag = 0U; mscHandle->cswPrimeFlag = 0U; break; case kUSB_DeviceClassEventSetConfiguration: /* Get the new configuration. */ temp8 = ((uint8_t *)param); if (NULL == mscHandle->configurationStruct) { break; } if (*temp8 == mscHandle->configuration) { error = kStatus_USB_Success; break; } if (0U != mscHandle->configuration) { /* De-initialize the endpoints when current configuration is none zero. */ error = USB_DeviceMscEndpointsDeinit(mscHandle); } /* Save new configuration. */ mscHandle->configuration = *temp8; /* Clear the alternate setting value. */ mscHandle->alternate = 0; /* Initialize the endpoints of the new current configuration by using the alternate setting 0. */ error = USB_DeviceMscEndpointsInit(mscHandle); if (kStatus_USB_Success == error) { #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH); #endif mscHandle->cbwPrimeFlag = 1U; } break; case kUSB_DeviceClassEventSetInterface: if (NULL == mscHandle->configurationStruct) { break; } /* Get the new alternate setting of the interface */ interfaceAlternate = *((uint16_t *)param); /* Get the alternate setting value */ alternate = (uint8_t)(interfaceAlternate & 0xFFU); /* Whether the interface belongs to the class. */ if (mscHandle->interfaceNumber != ((uint8_t)(interfaceAlternate >> 8))) { break; } /* Only handle new alternate setting. */ if (alternate == mscHandle->alternate) { error = kStatus_USB_Success; break; } error = USB_DeviceMscEndpointsDeinit(mscHandle); /* Initialize new endpoints */ error = USB_DeviceMscEndpointsInit(mscHandle); if (kStatus_USB_Success == error) { #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH); #endif mscHandle->cbwPrimeFlag = 1U; } mscHandle->alternate = alternate; break; case kUSB_DeviceClassEventSetEndpointHalt: if ((NULL == mscHandle->configurationStruct) || (NULL == mscHandle->interfaceHandle)) { break; } /* Get the endpoint address */ temp8 = ((uint8_t *)param); if ((mscHandle->inEndpointStallFlag == 0U) && (*temp8 == mscHandle->bulkInEndpoint)) { /* Only stall the endpoint belongs to the class */ mscHandle->inEndpointStallFlag = 1U; mscHandle->cswPrimeFlag = 0U; error = USB_DeviceStallEndpoint(mscHandle->handle, *temp8); } if ((mscHandle->outEndpointStallFlag == 0U) && (*temp8 == mscHandle->bulkOutEndpoint)) { mscHandle->outEndpointStallFlag = 1U; mscHandle->cbwPrimeFlag = 0U; error = USB_DeviceStallEndpoint(mscHandle->handle, *temp8); } break; case kUSB_DeviceClassEventClearEndpointHalt: if ((NULL == mscHandle->configurationStruct) || (NULL == mscHandle->interfaceHandle) || (mscHandle->performResetRecover == 1U)) { break; } /* Get the endpoint address */ temp8 = ((uint8_t *)param); /* Only un-stall the endpoint belongs to the class , If the endpoint is in stall status ,then * un-stall it*/ if ((mscHandle->inEndpointStallFlag == 1U) && (*temp8 == mscHandle->bulkInEndpoint)) { mscHandle->inEndpointStallFlag = 0; mscHandle->cswPrimeFlag = 0; error = USB_DeviceUnstallEndpoint(mscHandle->handle, *temp8); } if ((mscHandle->outEndpointStallFlag == 1U) && (*temp8 == mscHandle->bulkOutEndpoint)) { mscHandle->outEndpointStallFlag = 0U; mscHandle->cbwPrimeFlag = 0U; error = USB_DeviceUnstallEndpoint(mscHandle->handle, *temp8); } if (((mscHandle->stallStatus == (uint8_t)USB_DEVICE_MSC_STALL_IN_CSW) || (mscHandle->stallStatus == (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA)) && (mscHandle->performResetDoneFlag != 1U)) { if (mscHandle->cswPrimeFlag == 1U) { /*cancel the transfer , after the cancel to be complete, and then prime csw in bulk in callback, */ mscHandle->inEndpointCswCancelFlag = 1U; #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceCancel(mscHandle->handle, mscHandle->bulkInEndpoint)) { return kStatus_USB_Error; } #else (void)USB_DeviceCancel(mscHandle->handle, mscHandle->bulkInEndpoint); #endif } else { /*send csw*/ mscHandle->mscCsw->dataResidue = USB_LONG_TO_LITTLE_ENDIAN(mscHandle->mscCsw->dataResidue); #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->mscCsw, USB_DEVICE_MSC_CSW_LENGTH); #endif mscHandle->cswPrimeFlag = 1U; } mscHandle->stallStatus = 0U; } if ((mscHandle->performResetDoneFlag == 1U) && (mscHandle->inEndpointStallFlag == 0U) && (mscHandle->outEndpointStallFlag == 0U)) { mscHandle->performResetDoneFlag = 0U; if (mscHandle->cbwPrimeFlag == 1U) { mscHandle->cbwPrimeFlag = 0U; #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceCancel(mscHandle->handle, mscHandle->bulkOutEndpoint)) { return kStatus_USB_Error; } #else (void)USB_DeviceCancel(mscHandle->handle, mscHandle->bulkOutEndpoint); #endif } else { /*prime cbw for new transfer*/ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH)) { return kStatus_USB_Error; } #else (void)USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->mscCbw, USB_DEVICE_MSC_CBW_LENGTH); #endif mscHandle->cbwPrimeFlag = 1U; } mscHandle->stallStatus = 0; } break; case kUSB_DeviceClassEventClassRequest: { /* Handle the msc class specific request. */ usb_device_control_request_struct_t *control_request = (usb_device_control_request_struct_t *)param; if ((control_request->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_INTERFACE) { break; } if ((control_request->setup->wIndex & 0xFFU) != mscHandle->interfaceNumber) { break; } error = kStatus_USB_InvalidRequest; switch (control_request->setup->bRequest) { case USB_DEVICE_MSC_GET_MAX_LUN: /*Get Max LUN */ if ((0U == control_request->setup->wValue) && (control_request->setup->wLength == 0x0001U) && ((control_request->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN)) { control_request->buffer = &mscHandle->logicalUnitNumber; control_request->length = sizeof(mscHandle->logicalUnitNumber); error = kStatus_USB_Success; } break; case USB_DEVICE_MSC_BULK_ONLY_MASS_STORAGE_RESET: /*Bulk-Only Mass Storage Reset (class-specific request)*/ if ((0U == control_request->setup->wValue) && (0U == control_request->setup->wLength) && ((control_request->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT)) { /*Need to go to stall process, because reset recovery contains reset command and clare * feature command*/ mscHandle->outEndpointStallFlag = 1U; mscHandle->inEndpointStallFlag = 1U; mscHandle->cbwValidFlag = 1U; mscHandle->performResetRecover = 0U; mscHandle->performResetDoneFlag = 1U; error = kStatus_USB_Success; } break; default: /* no action, return kStatus_USB_InvalidRequest */ break; } } break; default: /*no action*/ break; } return error; } /*! * @brief Send data through a specified endpoint. * * The function is used to send data through a specified endpoint. * The function calls USB_DeviceSendRequest internally. * * @param handle The msc class handle got from usb_device_class_config_struct_t::classHandle. * * @return A USB error code or kStatus_USB_Success. * * @note The return value just means if the sending request is successful or not; the transfer done is notified by * USB_DeviceMscBulkIn. * Currently, only one transfer request can be supported for one specific endpoint. * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application * should implement a queue in the application level. * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint * callback). */ usb_status_t USB_DeviceMscSend(usb_device_msc_struct_t *mscHandle) { usb_status_t status = kStatus_USB_Success; usb_device_lba_app_struct_t lba; lba.offset = mscHandle->currentOffset; /*bulkInBufferSize is the application buffer size, USB_DEVICE_MSC_MAX_SEND_TRANSFER_LENGTH is the max transfer length by the hardware, lba.size is the data pending for transfer ,select the minimum size to transfer ,the remaining will be transfer next time*/ lba.size = (mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].bulkInBufferSize > USB_DEVICE_MSC_MAX_SEND_TRANSFER_LENGTH) ? USB_DEVICE_MSC_MAX_SEND_TRANSFER_LENGTH : mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].bulkInBufferSize; lba.size = (mscHandle->transferRemaining > lba.size) ? lba.size : mscHandle->transferRemaining; /* which one is smaller */ lba.buffer = NULL; lba.lun = mscHandle->mscCbw->logicalUnitNumber; /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit*/ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventReadRequest, &lba)) { return kStatus_USB_Error; } #else (void)mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventReadRequest, &lba); #endif if (mscHandle->currentOffset < mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].totalLbaNumberSupports) { status = USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, lba.buffer, lba.size); } else { mscHandle->needInStallFlag = 0U; mscHandle->inEndpointStallFlag = 1U; mscHandle->dataInFlag = 0U; mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA; #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkInEndpoint)) { return kStatus_USB_Error; } #else (void)USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkInEndpoint); #endif } return status; } /*! * @brief Receive data through a specified endpoint. * * The function is used to receive data through a specified endpoint. * The function calls USB_DeviceRecvRequest internally. * * @param handle The msc class handle got from usb_device_class_config_struct_t::classHandle. * * @return A USB error code or kStatus_USB_Success. * * @note The return value just means if the receiving request is successful or not; the transfer done is notified by * USB_DeviceMscBulkOut. * Currently, only one transfer request can be supported for one specific endpoint. * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application * should implement a queue in the application level. * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint * callback). */ usb_status_t USB_DeviceMscRecv(usb_device_msc_struct_t *mscHandle) { usb_status_t status = kStatus_USB_Success; usb_device_lba_app_struct_t lba; lba.offset = mscHandle->currentOffset; /*bulkOutBufferSize is the application buffer size, USB_DEVICE_MSC_MAX_RECV_TRANSFER_LENGTH is the max transfer length by the hardware, lba.size is the data pending for transfer ,select the minimum size to transfer ,the remaining will be transfer next time*/ lba.size = (mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].bulkOutBufferSize > USB_DEVICE_MSC_MAX_RECV_TRANSFER_LENGTH) ? USB_DEVICE_MSC_MAX_RECV_TRANSFER_LENGTH : mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].bulkOutBufferSize; lba.size = (mscHandle->transferRemaining > lba.size) ? lba.size : mscHandle->transferRemaining; /* whichever is smaller */ lba.buffer = NULL; lba.lun = mscHandle->mscCbw->logicalUnitNumber; /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit*/ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventWriteRequest, &lba)) { return kStatus_USB_Error; } #else (void)mscHandle->configurationStruct->classCallback((class_handle_t)mscHandle, kUSB_DeviceMscEventWriteRequest, &lba); #endif if (mscHandle->currentOffset < mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].totalLbaNumberSupports) { status = USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, lba.buffer, lba.size); } else { mscHandle->needOutStallFlag = 0U; mscHandle->outEndpointStallFlag = 1U; mscHandle->dataOutFlag = 0U; mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA; #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) if (kStatus_USB_Success != USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkOutEndpoint)) { return kStatus_USB_Error; } #else (void)USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkOutEndpoint); #endif } return status; } /*! * @brief Recv Send data through a specified endpoint. * * The function is used when ufi process read/write command . * The function calls USB_DeviceMscRecv or usb_device_send_recv as the direction internally. * * @param handle The msc class handle got from usb_device_class_config_struct_t::classHandle. * @param direction Data direction: 0 = Data-Out from host to the device, 1 = Data-In from the device to the host. * @param buffer The memory address to hold the data need to be sent. * @return A USB error code or kStatus_USB_Success. * * @note The return value just means if the sending or receiving request is successful or not. */ usb_status_t USB_DeviceMscLbaTransfer(usb_device_msc_struct_t *mscHandle, uint8_t direction, usb_lba_transfer_information_struct_t *lba_info_ptr) { usb_status_t error = kStatus_USB_Success; mscHandle->transferRemaining = lba_info_ptr->transferNumber * mscHandle->luInformations[mscHandle->mscCbw->logicalUnitNumber].lengthOfEachLba; mscHandle->currentOffset = lba_info_ptr->startingLogicalBlockAddress; if (direction == USB_IN) { error = USB_DeviceMscSend(mscHandle); } else { error = USB_DeviceMscRecv(mscHandle); } return error; } #endif