MCUXpresso_MIMXRT1052xxxxB/boards/evkbimxrt1050/usb_examples/usb_device_composite_cdc_msc_lite/bm/disk.c
2022-08-24 23:30:23 +08:00

833 lines
34 KiB
C

/*
* Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
* Copyright 2016 - 2017, 2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdio.h>
#include <stdlib.h>
/*${standard_header_anchor}*/
#include "usb_device_config.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_msc.h"
#include "usb_device_ch9.h"
#include "usb_device_descriptor.h"
#include "disk.h"
#include "fsl_device_registers.h"
#include "clock_config.h"
#include "fsl_debug_console.h"
#include "board.h"
#include "composite.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint8_t s_StorageDisk[DISK_SIZE_NORMAL];
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) usb_device_msc_cbw_t s_MscCbw;
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) usb_device_msc_csw_t s_MscCsw;
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) usb_device_request_sense_data_struct_t g_requestSense;
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) usb_device_read_capacity_struct_t g_readCapacity;
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) usb_device_read_capacity16_data_struct_t g_readCapacity16;
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
uint8_t g_formatCapacityData[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];
static usb_device_composite_struct_t *g_deviceComposite;
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
usb_device_inquiry_data_fromat_struct_t g_InquiryInfo = {
(USB_DEVICE_MSC_UFI_PERIPHERAL_QUALIFIER << USB_DEVICE_MSC_UFI_PERIPHERAL_QUALIFIER_SHIFT) |
USB_DEVICE_MSC_UFI_PERIPHERAL_DEVICE_TYPE,
(uint8_t)(USB_DEVICE_MSC_UFI_REMOVABLE_MEDIUM_BIT << USB_DEVICE_MSC_UFI_REMOVABLE_MEDIUM_BIT_SHIFT),
USB_DEVICE_MSC_UFI_VERSIONS,
0x02,
USB_DEVICE_MSC_UFI_ADDITIONAL_LENGTH,
{0x00, 0x00, 0x00},
{'N', 'X', 'P', ' ', 'S', 'E', 'M', 'I'},
{'N', 'X', 'P', ' ', 'M', 'A', 'S', 'S', ' ', 'S', 'T', 'O', 'R', 'A', 'G', 'E'},
{'0', '0', '0', '1'}};
USB_DMA_INIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE)
usb_device_mode_parameters_header_struct_t g_ModeParametersHeader = {
/*refer to ufi spec mode parameter header*/
0x0000, /*!< Mode Data Length*/
0x00, /*!<Default medium type (current mounted medium type)*/
0x00, /*!MODE SENSE command, a Write Protected bit of zero indicates the medium is write enabled*/
{0x00, 0x00, 0x00, 0x00} /*!<This bit should be set to zero*/
};
/*******************************************************************************
* Code
******************************************************************************/
usb_status_t USB_DeviceMscSend(usb_device_msc_struct_t *mscHandle)
{
usb_status_t error = 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->bulkInBufferSize > USB_DEVICE_MSC_MAX_SEND_TRANSFER_LENGTH) ?
USB_DEVICE_MSC_MAX_SEND_TRANSFER_LENGTH :
mscHandle->bulkInBufferSize;
lba.size =
(mscHandle->transferRemaining > lba.size) ? lba.size : mscHandle->transferRemaining; /* whichever is smaller */
lba.buffer = g_deviceComposite->mscDisk.storageDisk + lba.offset * mscHandle->lengthOfEachLba;
if (mscHandle->currentOffset < (mscHandle->totalLogicalBlockNumber))
{
error = USB_DeviceSendRequest(g_deviceComposite->deviceHandle, mscHandle->bulkInEndpoint, lba.buffer, lba.size);
}
else
{
mscHandle->needInStallFlag = 0;
mscHandle->inEndpointStallFlag = 1;
mscHandle->dataInFlag = 0;
mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA;
USB_DeviceStallEndpoint(g_deviceComposite->deviceHandle, mscHandle->bulkInEndpoint);
}
return error;
}
/*!
* @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 error = 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->bulkOutBufferSize > USB_DEVICE_MSC_MAX_RECV_TRANSFER_LENGTH) ?
USB_DEVICE_MSC_MAX_RECV_TRANSFER_LENGTH :
mscHandle->bulkOutBufferSize;
lba.size =
(mscHandle->transferRemaining > lba.size) ? lba.size : mscHandle->transferRemaining; /* whichever is smaller */
lba.buffer = g_deviceComposite->mscDisk.storageDisk + lba.offset * mscHandle->lengthOfEachLba;
if (mscHandle->currentOffset < (mscHandle->totalLogicalBlockNumber))
{
error =
USB_DeviceRecvRequest(g_deviceComposite->deviceHandle, mscHandle->bulkOutEndpoint, lba.buffer, lba.size);
}
else
{
mscHandle->needOutStallFlag = 0;
mscHandle->outEndpointStallFlag = 1;
mscHandle->dataOutFlag = 0;
mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA;
USB_DeviceStallEndpoint(g_deviceComposite->deviceHandle, mscHandle->bulkOutEndpoint);
}
return error;
}
/*!
* @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_deviceSendRecv 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 *lbaInformation)
{
usb_status_t error = kStatus_USB_Success;
mscHandle->transferRemaining = lbaInformation->transferNumber * mscHandle->lengthOfEachLba;
mscHandle->currentOffset = lbaInformation->startingLogicalBlockAddress;
if (direction == USB_IN)
{
error = USB_DeviceMscSend(mscHandle);
}
else
{
error = USB_DeviceMscRecv(mscHandle);
}
return error;
}
/*!
* @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.
*/
usb_status_t USB_DeviceMscProcessUfiCommand(usb_device_msc_struct_t *mscHandle)
{
usb_status_t error = kStatus_USB_Error;
usb_device_msc_ufi_struct_t *ufi = NULL;
ufi = &mscHandle->g_mscUfi;
if (USB_DEVICE_MSC_REQUEST_SENSE_COMMAND != mscHandle->g_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->g_mscCbw->dataTransferLength;
ufi->thirteenCase.hostExpectedDirection =
(uint8_t)(mscHandle->g_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->g_mscCbw->cbwcb[0])
{
/* ufi command operation code*/
case USB_DEVICE_MSC_INQUIRY_COMMAND: /*operation code : 0x12*/
error = USB_DeviceMscUfiInquiryCommand(mscHandle);
break;
case USB_DEVICE_MSC_READ_10_COMMAND: /*operation code : 0x28 */
case USB_DEVICE_MSC_READ_12_COMMAND: /*operation code : 0xA8 */
error = USB_DeviceMscUfiReadCommand(mscHandle);
break;
case USB_DEVICE_MSC_REQUEST_SENSE_COMMAND: /*operation code : 0x03*/
error = USB_DeviceMscUfiRequestSenseCommand(mscHandle);
break;
case USB_DEVICE_MSC_TEST_UNIT_READY_COMMAND: /*operation code : 0x00 */
if (1U == g_deviceComposite->mscDisk.stop)
{
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_NOT_READY;
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_ASC_MEDIUM_NOT_PRESENT;
}
error = USB_DeviceMscUfiTestUnitReadyCommand(mscHandle);
break;
case USB_DEVICE_MSC_WRITE_10_COMMAND: /*operation code : 0x2A */
case USB_DEVICE_MSC_WRITE_12_COMMAND: /*operation code : 0xAA */
error = USB_DeviceMscUfiWriteCommand(mscHandle);
break;
case USB_DEVICE_MSC_PREVENT_ALLOW_MEDIUM_REM_COMMAND: /*operation code :0x1E */
error = USB_DeviceMscUfiPreventAllowMediumCommand(mscHandle);
break;
case USB_DEVICE_MSC_FORMAT_UNIT_COMMAND: /*operation code : 0x04*/
error = 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*/
error = 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 */
error = 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 */
error = USB_DeviceMscUfiModeSelectCommand(mscHandle);
break;
case USB_DEVICE_MSC_READ_FORMAT_CAPACITIES_COMMAND: /*operation code : 0x23 */
error = USB_DeviceMscUfiReadFormatCapacityCommand(mscHandle);
break;
case USB_DEVICE_MSC_SEND_DIAGNOSTIC_COMMAND: /*operation code : 0x1D*/
error = USB_DeviceMscUfiSendDiagnosticCommand(mscHandle);
break;
case USB_DEVICE_MSC_VERIFY_COMMAND: /*operation code : 0x2F*/
error = USB_DeviceMscUfiVerifyCommand(mscHandle);
break;
case USB_DEVICE_MSC_START_STOP_UNIT_COMMAND: /*operation code : 0x1B*/
if (0x00U == (mscHandle->g_mscCbw->cbwcb[4] & 0x01U)) /* check start bit */
{
g_deviceComposite->mscDisk.stop = 1U; /* stop command */
}
error = USB_DeviceMscUfiStartStopUnitCommand(mscHandle);
break;
default:
error = USB_DeviceMscUfiUnsupportCommand(mscHandle);
mscHandle->dataOutFlag = 0;
mscHandle->dataInFlag = 0;
mscHandle->outEndpointStallFlag = 0;
mscHandle->inEndpointStallFlag = 0;
mscHandle->needOutStallFlag = 0;
mscHandle->needInStallFlag = 0;
break;
}
if ((USB_DEVICE_MSC_UFI_NO_SENSE != ufi->requestSense->senseKey) &&
(USB_DEVICE_MSC_COMMAND_PASSED == mscHandle->g_mscCsw->cswStatus) &&
(USB_DEVICE_MSC_REQUEST_SENSE_COMMAND != mscHandle->g_mscCbw->cbwcb[0]))
{
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
}
return error;
}
/*!
* @brief Bulk IN endpoint callback function.
*
* This callback function is used to notify upper layer the transfered 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 event The result of the Bulk IN pipe transfer.
* @param arg 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.
*/
usb_status_t USB_DeviceMscBulkIn(usb_device_handle deviceHandle,
usb_device_endpoint_callback_message_struct_t *event,
void *arg)
{
usb_device_msc_csw_t *csw = NULL;
usb_status_t error = kStatus_USB_Error;
usb_device_msc_struct_t *mscHandle;
mscHandle = &(g_deviceComposite->mscDisk.handle);
/* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */
if (event->length == USB_CANCELLED_TRANSFER_LENGTH)
{
if (mscHandle->inEndpointCswCancelFlag == 1)
{
mscHandle->inEndpointCswCancelFlag = 0;
/*cancel the transfer and wait for the calcel to be complete in bulk in callback*/
/*send csw*/
USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->g_mscCsw,
USB_DEVICE_MSC_CSW_LENGTH);
mscHandle->cswPrimeFlag = 1;
mscHandle->stallStatus = 0;
}
return error;
}
if (mscHandle->transferRemaining >= event->length)
{
mscHandle->transferRemaining -= event->length;
}
if (mscHandle->needInStallFlag == 1)
{
mscHandle->needInStallFlag = 0;
mscHandle->inEndpointStallFlag = 1;
mscHandle->dataInFlag = 0;
USB_DeviceStallEndpoint(deviceHandle, mscHandle->bulkInEndpoint);
return error;
}
if ((!mscHandle->dataInFlag) && (event->length == USB_DEVICE_MSC_CSW_LENGTH))
{
csw = (usb_device_msc_csw_t *)(event->buffer);
}
if (mscHandle->dataInFlag)
{
if (mscHandle->transferRemaining)
{
mscHandle->currentOffset += (event->length / mscHandle->lengthOfEachLba);
error = USB_DeviceMscSend(mscHandle);
}
if (!mscHandle->transferRemaining)
{
mscHandle->dataInFlag = 0;
/*data transfer has been done, send the csw to host */
mscHandle->cswPrimeFlag = 1;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
error = USB_DeviceSendRequest(deviceHandle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->g_mscCsw,
USB_DEVICE_MSC_CSW_LENGTH);
#else
(void)USB_DeviceSendRequest(deviceHandle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->g_mscCsw,
USB_DEVICE_MSC_CSW_LENGTH);
#endif
}
}
else if ((event->length == USB_DEVICE_MSC_CSW_LENGTH) && (csw->signature == USB_DEVICE_MSC_DCSWSIGNATURE))
{
mscHandle->cbwValidFlag = 1;
mscHandle->cswPrimeFlag = 0;
#if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
error = UUSB_DeviceRecvRequest(deviceHandle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->g_mscCbw,
USB_DEVICE_MSC_CBW_LENGTH);
#else
(void)USB_DeviceRecvRequest(deviceHandle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->g_mscCbw,
USB_DEVICE_MSC_CBW_LENGTH);
#endif
mscHandle->cbwPrimeFlag = 1;
}
else
{
}
return error;
}
/*!
* @brief Bulk OUT endpoint callback function.
*
* This callback function is used to notify upper layer the transfered 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.
*/
usb_status_t USB_DeviceMscBulkOut(usb_device_handle deviceHandle,
usb_device_endpoint_callback_message_struct_t *event,
void *arg)
{
usb_status_t error = kStatus_USB_Success;
usb_device_msc_struct_t *mscHandle;
mscHandle = &(g_deviceComposite->mscDisk.handle);
/* endpoint callback length is USB_CANCELLED_TRANSFER_LENGTH (0xFFFFFFFFU) when transfer is canceled */
if (event->length == USB_CANCELLED_TRANSFER_LENGTH)
{
if ((mscHandle->cbwPrimeFlag == 0) && (mscHandle->inEndpointStallFlag == 0) &&
(mscHandle->outEndpointStallFlag == 0))
{
/*prime cbw*/
USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->g_mscCbw,
USB_DEVICE_MSC_CBW_LENGTH);
mscHandle->cbwPrimeFlag = 1;
}
return error;
}
if (mscHandle->transferRemaining >= event->length)
{
mscHandle->transferRemaining -= event->length;
}
if (mscHandle->needOutStallFlag == 1)
{
mscHandle->needOutStallFlag = 0;
mscHandle->outEndpointStallFlag = 1;
mscHandle->dataOutFlag = 0;
mscHandle->cbwPrimeFlag = 0;
USB_DeviceStallEndpoint(deviceHandle, mscHandle->bulkOutEndpoint);
return error;
}
if (mscHandle->dataOutFlag)
{
if (mscHandle->transferRemaining)
{
mscHandle->currentOffset += (event->length / mscHandle->lengthOfEachLba);
error = USB_DeviceMscRecv(mscHandle);
}
if (!mscHandle->transferRemaining)
{
mscHandle->dataOutFlag = 0;
{
USB_DeviceSendRequest(deviceHandle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->g_mscCsw,
USB_DEVICE_MSC_CSW_LENGTH);
mscHandle->cswPrimeFlag = 1;
}
}
}
else if ((mscHandle->cbwValidFlag) && (event->length == USB_DEVICE_MSC_CBW_LENGTH) &&
(mscHandle->g_mscCbw->signature == USB_DEVICE_MSC_DCBWSIGNATURE) &&
(!((mscHandle->g_mscCbw->logicalUnitNumber & 0xF0U) || (mscHandle->g_mscCbw->cbLength & 0xE0U))) &&
(mscHandle->g_mscCbw->logicalUnitNumber < (mscHandle->logicalUnitNumber + 1)) &&
((mscHandle->g_mscCbw->cbLength >= 0x01) && (mscHandle->g_mscCbw->cbLength <= 0x10)))
{
mscHandle->cbwPrimeFlag = 0;
mscHandle->transferRemaining = 0;
mscHandle->g_mscCsw->signature = USB_DEVICE_MSC_DCSWSIGNATURE;
mscHandle->g_mscCsw->dataResidue = 0;
mscHandle->g_mscCsw->tag = mscHandle->g_mscCbw->tag;
mscHandle->cbwValidFlag = 0;
mscHandle->g_mscCbw->dataTransferLength = USB_LONG_FROM_LITTLE_ENDIAN(mscHandle->g_mscCbw->dataTransferLength);
mscHandle->dataOutFlag = (uint8_t)(((!(mscHandle->g_mscCbw->flags & USB_DEVICE_MSC_CBW_DIRECTION_BIT)) &&
(mscHandle->g_mscCbw->dataTransferLength)) ?
1 :
0);
mscHandle->dataInFlag = (uint8_t)(((mscHandle->g_mscCbw->flags & USB_DEVICE_MSC_CBW_DIRECTION_BIT) &&
(mscHandle->g_mscCbw->dataTransferLength)) ?
1 :
0);
if ((0 != mscHandle->dataInFlag) && (0 != mscHandle->inEndpointStallFlag))
{
error = kStatus_USB_Error;
return error;
}
error = USB_DeviceMscProcessUfiCommand(mscHandle);
if (error == kStatus_USB_InvalidRequest)
{
if (mscHandle->dataOutFlag == 1)
{
if (mscHandle->outEndpointStallFlag == 0)
{
mscHandle->needOutStallFlag = 1;
}
mscHandle->dataOutFlag = 0;
}
else if (mscHandle->dataInFlag == 1)
{
if (mscHandle->inEndpointStallFlag == 0)
{
mscHandle->needInStallFlag = 1;
}
mscHandle->dataInFlag = 0;
}
else
{
}
mscHandle->stallStatus = (uint8_t)USB_DEVICE_MSC_STALL_IN_DATA;
}
if (!((mscHandle->dataOutFlag) || ((mscHandle->dataInFlag) || (mscHandle->needInStallFlag))))
{
USB_DeviceSendRequest(deviceHandle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->g_mscCsw,
USB_DEVICE_MSC_CSW_LENGTH);
mscHandle->cswPrimeFlag = 1;
}
}
else
{
USB_DeviceStallEndpoint(deviceHandle, mscHandle->bulkOutEndpoint);
USB_DeviceStallEndpoint(deviceHandle, mscHandle->bulkInEndpoint);
mscHandle->cbwPrimeFlag = 0;
mscHandle->cbwValidFlag = 0;
mscHandle->outEndpointStallFlag = 1;
mscHandle->inEndpointStallFlag = 1;
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.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceMscEndpointsInit(void)
{
usb_status_t error = kStatus_USB_Error;
usb_device_endpoint_init_struct_t epInitStruct;
usb_device_endpoint_callback_struct_t epCallback;
usb_device_msc_struct_t *mscHandle;
mscHandle = &(g_deviceComposite->mscDisk.handle);
epCallback.callbackFn = USB_DeviceMscBulkIn;
epCallback.callbackParam = (void *)mscHandle;
epInitStruct.zlt = 0;
epInitStruct.interval = 0;
epInitStruct.transferType = USB_ENDPOINT_BULK;
epInitStruct.endpointAddress =
USB_MSC_DISK_BULK_IN_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
mscHandle->bulkInEndpoint = epInitStruct.endpointAddress;
if (USB_SPEED_HIGH == g_deviceComposite->speed)
{
epInitStruct.maxPacketSize = HS_MSC_DISK_BULK_IN_PACKET_SIZE;
}
else
{
epInitStruct.maxPacketSize = FS_MSC_DISK_BULK_IN_PACKET_SIZE;
}
USB_DeviceInitEndpoint(g_deviceComposite->deviceHandle, &epInitStruct, &epCallback);
epCallback.callbackFn = USB_DeviceMscBulkOut;
epCallback.callbackParam = (void *)mscHandle;
epInitStruct.zlt = 0;
epInitStruct.interval = 0;
epInitStruct.transferType = USB_ENDPOINT_BULK;
epInitStruct.endpointAddress =
USB_MSC_DISK_BULK_OUT_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
mscHandle->bulkOutEndpoint = epInitStruct.endpointAddress;
if (USB_SPEED_HIGH == g_deviceComposite->speed)
{
epInitStruct.maxPacketSize = HS_MSC_DISK_BULK_OUT_PACKET_SIZE;
}
else
{
epInitStruct.maxPacketSize = FS_MSC_DISK_BULK_OUT_PACKET_SIZE;
}
USB_DeviceInitEndpoint(g_deviceComposite->deviceHandle, &epInitStruct, &epCallback);
mscHandle->dataOutFlag = 0;
mscHandle->dataInFlag = 0;
mscHandle->outEndpointStallFlag = 0;
mscHandle->inEndpointStallFlag = 0;
mscHandle->needOutStallFlag = 0;
mscHandle->needInStallFlag = 0;
mscHandle->cbwValidFlag = 1;
mscHandle->transferRemaining = 0;
mscHandle->performResetRecover = 0;
mscHandle->performResetDoneFlag = 0;
mscHandle->stallStatus = 0;
mscHandle->inEndpointCswCancelFlag = 0;
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.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceMscEndpointsDeinit(void)
{
usb_status_t error = kStatus_USB_Success;
usb_device_msc_struct_t *mscHandle;
mscHandle = &(g_deviceComposite->mscDisk.handle);
error = USB_DeviceDeinitEndpoint(g_deviceComposite->deviceHandle, mscHandle->bulkInEndpoint);
error = USB_DeviceDeinitEndpoint(g_deviceComposite->deviceHandle, mscHandle->bulkOutEndpoint);
return error;
}
usb_status_t USB_DeviceMscDiskConfigureEndpointStatus(usb_device_handle handle, uint8_t ep, uint8_t status)
{
usb_status_t error = kStatus_USB_Error;
usb_device_msc_struct_t *mscHandle;
mscHandle = &(g_deviceComposite->mscDisk.handle);
if (status)
{
if ((USB_MSC_DISK_BULK_IN_ENDPOINT == (ep & USB_ENDPOINT_NUMBER_MASK)) &&
(ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK))
{
if (mscHandle->inEndpointStallFlag == 0)
{
mscHandle->inEndpointStallFlag = 1;
mscHandle->cswPrimeFlag = 0;
error = USB_DeviceStallEndpoint(handle, ep);
}
}
else if ((USB_MSC_DISK_BULK_OUT_ENDPOINT == (ep & USB_ENDPOINT_NUMBER_MASK)) &&
(!(ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK)))
{
if (mscHandle->outEndpointStallFlag == 0)
{
mscHandle->outEndpointStallFlag = 1;
mscHandle->cbwPrimeFlag = 0;
error = USB_DeviceStallEndpoint(handle, ep);
}
}
else
{
}
}
else
{
if (mscHandle->performResetRecover == 1)
{
return error;
}
if ((USB_MSC_DISK_BULK_IN_ENDPOINT == (ep & USB_ENDPOINT_NUMBER_MASK)) &&
(ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK))
{
if (mscHandle->inEndpointStallFlag == 1)
{
mscHandle->inEndpointStallFlag = 0;
mscHandle->cswPrimeFlag = 0;
error = USB_DeviceUnstallEndpoint(handle, ep);
}
}
else if ((USB_MSC_DISK_BULK_OUT_ENDPOINT == (ep & USB_ENDPOINT_NUMBER_MASK)) &&
(!(ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK)))
{
if (mscHandle->outEndpointStallFlag == 1)
{
mscHandle->outEndpointStallFlag = 0;
mscHandle->cbwPrimeFlag = 0;
error = USB_DeviceUnstallEndpoint(handle, ep);
}
}
else
{
}
if (((mscHandle->stallStatus == USB_DEVICE_MSC_STALL_IN_CSW) ||
(mscHandle->stallStatus == USB_DEVICE_MSC_STALL_IN_DATA)) &&
(mscHandle->performResetDoneFlag != 1))
{
if (mscHandle->cswPrimeFlag == 1)
{
/*cancel the transfer , after the cancel to be complete, and then prime csw in bulk out callback, */
mscHandle->inEndpointCswCancelFlag = 1;
USB_DeviceCancel(handle, mscHandle->bulkInEndpoint);
}
else
{
USB_DeviceSendRequest(handle, mscHandle->bulkInEndpoint, (uint8_t *)mscHandle->g_mscCsw,
USB_DEVICE_MSC_CSW_LENGTH);
mscHandle->cswPrimeFlag = 1;
}
mscHandle->stallStatus = 0;
}
if ((mscHandle->performResetDoneFlag == 1) && (mscHandle->inEndpointStallFlag == 0) &&
(mscHandle->outEndpointStallFlag == 0))
{
mscHandle->performResetDoneFlag = 0;
if (mscHandle->cbwPrimeFlag == 1)
{
mscHandle->cbwPrimeFlag = 0;
USB_DeviceCancel(handle, mscHandle->bulkOutEndpoint);
}
else
{
USB_DeviceRecvRequest(handle, mscHandle->bulkOutEndpoint, (uint8_t *)mscHandle->g_mscCbw,
USB_DEVICE_MSC_CBW_LENGTH);
mscHandle->cbwPrimeFlag = 1;
}
mscHandle->stallStatus = 0;
}
}
return error;
}
usb_status_t USB_DeviceMscDiskClassRequest(usb_device_handle handle,
usb_setup_struct_t *setup,
uint32_t *length,
uint8_t **buffer)
{
usb_status_t error = kStatus_USB_InvalidRequest;
usb_device_msc_struct_t *mscHandle;
mscHandle = &(g_deviceComposite->mscDisk.handle);
if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
{
return error;
}
switch (setup->bRequest)
{
case USB_DEVICE_MSC_GET_MAX_LUN:
if ((!setup->wValue) && (setup->wLength == 0x0001) &&
((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_IN))
{
*buffer = (uint8_t *)&mscHandle->logicalUnitNumber;
*length = sizeof(mscHandle->logicalUnitNumber);
error = kStatus_USB_Success;
}
break;
case USB_DEVICE_MSC_BULK_ONLY_MASS_STORAGE_RESET:
if ((!setup->wValue) && (!setup->wLength) &&
((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->cbwValidFlag = 1;
mscHandle->outEndpointStallFlag = 1;
mscHandle->inEndpointStallFlag = 1;
mscHandle->performResetRecover = 0;
mscHandle->performResetDoneFlag = 1;
error = kStatus_USB_Success;
}
break;
default:
break;
}
return error;
}
usb_status_t USB_DeviceMscDiskSetConfigure(usb_device_handle handle, uint8_t configure)
{
usb_status_t error = kStatus_USB_Error;
usb_device_msc_struct_t *mscHandle;
mscHandle = &(g_deviceComposite->mscDisk.handle);
if (g_deviceComposite->currentConfiguration == configure)
{
return error;
}
if (g_deviceComposite->currentConfiguration)
{
USB_DeviceMscEndpointsDeinit();
}
g_deviceComposite->mscDisk.attach = 1;
g_deviceComposite->mscDisk.stop = 0U;
if (USB_COMPOSITE_CONFIGURE_INDEX == configure)
{
error = USB_DeviceMscEndpointsInit();
USB_DeviceRecvRequest(g_deviceComposite->deviceHandle, mscHandle->bulkOutEndpoint,
(uint8_t *)mscHandle->g_mscCbw, USB_DEVICE_MSC_CBW_LENGTH);
mscHandle->cbwPrimeFlag = 1;
}
return error;
}
usb_status_t USB_DeviceMscDiskInit(usb_device_composite_struct_t *deviceComposite)
{
usb_device_msc_ufi_struct_t *ufi = NULL;
usb_device_msc_struct_t *mscHandle;
g_deviceComposite = deviceComposite;
g_deviceComposite->mscDisk.storageDisk = s_StorageDisk;
g_deviceComposite->mscDisk.storageDisk[0] = 0x01;
g_deviceComposite->mscDisk.handle.g_mscCbw = &s_MscCbw;
g_deviceComposite->mscDisk.handle.g_mscCsw = &s_MscCsw;
mscHandle = &(g_deviceComposite->mscDisk.handle);
mscHandle->handle = deviceComposite->deviceHandle;
ufi = &mscHandle->g_mscUfi;
mscHandle->totalLogicalBlockNumber = TOTAL_LOGICAL_ADDRESS_BLOCKS_NORMAL;
mscHandle->lengthOfEachLba = LENGTH_OF_EACH_LBA;
mscHandle->logicalUnitNumber = LOGICAL_UNIT_SUPPORTED - 1;
mscHandle->bulkInBufferSize = DISK_SIZE_NORMAL;
mscHandle->bulkOutBufferSize = DISK_SIZE_NORMAL;
mscHandle->implementingDiskDrive = USB_DEVICE_CONFIG_MSC_IMPLEMENTING_DISK_DRIVE;
if (mscHandle->lengthOfEachLba * mscHandle->totalLogicalBlockNumber == 0)
{
return kStatus_USB_Error;
}
ufi->requestSense = &g_requestSense;
ufi->readCapacity = &g_readCapacity;
ufi->readCapacity16 = &g_readCapacity16;
ufi->formatCapacityData = &g_formatCapacityData[0];
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;
ufi->readCapacity->lastLogicalBlockAddress = USB_LONG_TO_BIG_ENDIAN(mscHandle->totalLogicalBlockNumber - 1);
ufi->readCapacity->blockSize = USB_LONG_TO_BIG_ENDIAN((uint32_t)mscHandle->lengthOfEachLba);
ufi->readCapacity16->lastLogicalBlockAddress1 = USB_LONG_TO_BIG_ENDIAN(mscHandle->totalLogicalBlockNumber - 1);
ufi->readCapacity16->blockSize = USB_LONG_TO_BIG_ENDIAN((uint32_t)mscHandle->lengthOfEachLba);
mscHandle->cbwPrimeFlag = 0;
mscHandle->cswPrimeFlag = 0;
return kStatus_USB_Success;
}