833 lines
32 KiB
C
833 lines
32 KiB
C
/*
|
|
* Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
|
|
* Copyright 2016 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "usb_device_config.h"
|
|
#include "usb.h"
|
|
#include "usb_device.h"
|
|
|
|
#if USB_DEVICE_CONFIG_MSC
|
|
#include "usb_device_msc_ufi.h"
|
|
#include "usb_device_msc.h"
|
|
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
extern usb_device_inquiry_data_fromat_struct_t g_InquiryInfo;
|
|
extern usb_device_mode_parameters_header_struct_t g_ModeParametersHeader;
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
|
|
/*!
|
|
* @brief Thirteen possible case check.
|
|
*
|
|
* This function handle the thirteen possible cases of host expectations and device intent in the absence of
|
|
*overriding error conditions.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success. more information about return value ,refer to
|
|
*USB_DeviceMscLbaTransfer and USB_DeviceRecvRequest
|
|
*/
|
|
|
|
usb_status_t USB_DeviceMscUfiThirteenCasesCheck(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_status_t error = kStatus_USB_Success;
|
|
usb_device_msc_ufi_struct_t *ufi;
|
|
usb_device_msc_thirteen_case_struct_t *mscCheckEvent;
|
|
|
|
mscCheckEvent = (usb_device_msc_thirteen_case_struct_t *)&mscHandle->g_mscUfi.thirteenCase;
|
|
ufi = &mscHandle->g_mscUfi;
|
|
/* The following code describe the thirteen possible cases of host
|
|
expectations and device intent in absence of overriding error conditions ,refer to bulk-only spec chapter 6.7
|
|
The Thirteen Cases*/
|
|
if (mscCheckEvent->hostExpectedDataLength == 0)
|
|
{
|
|
/*Host expects no data transfers*/
|
|
mscHandle->g_mscCsw->dataResidue = 0;
|
|
if (mscCheckEvent->deviceExpectedDataLength == 0)
|
|
{ /*case 1, Device intends to transfer no data*/
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
else
|
|
{ /*case 2 ,Device intends to send data to the host; */
|
|
/*case 3, Device intends to receive data from the host*/
|
|
/*set csw status to 02h*/
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_PHASE_ERROR;
|
|
}
|
|
}
|
|
else if (mscCheckEvent->hostExpectedDirection)
|
|
{
|
|
/*Host expects to receive data from the device*/
|
|
if (mscCheckEvent->deviceExpectedDataLength == 0)
|
|
{
|
|
/*case 4, Device intends to transfer no data*/
|
|
mscHandle->g_mscCsw->dataResidue =
|
|
mscCheckEvent->hostExpectedDataLength - mscCheckEvent->deviceExpectedDataLength;
|
|
error = USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, mscCheckEvent->buffer,
|
|
mscCheckEvent->deviceExpectedDataLength);
|
|
|
|
if (kStatus_USB_Success == error)
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_MEDIUM_ERROR;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_UNRECOVERED_READ_ERROR;
|
|
}
|
|
error = kStatus_USB_InvalidRequest;
|
|
}
|
|
else if (mscCheckEvent->deviceExpectedDirection)
|
|
{
|
|
if (mscCheckEvent->hostExpectedDataLength > mscCheckEvent->deviceExpectedDataLength)
|
|
{
|
|
/*case 5, device intends to send less data than the host indicated*/
|
|
mscHandle->g_mscCsw->dataResidue =
|
|
mscCheckEvent->hostExpectedDataLength - mscCheckEvent->deviceExpectedDataLength;
|
|
|
|
if (ufi->thirteenCase.lbaSendRecvSelect == 1)
|
|
{
|
|
error = USB_DeviceMscLbaTransfer(mscHandle, USB_IN, &mscCheckEvent->lbaInformation);
|
|
}
|
|
else
|
|
{
|
|
error = USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, mscCheckEvent->buffer,
|
|
mscCheckEvent->deviceExpectedDataLength);
|
|
}
|
|
|
|
if (kStatus_USB_Success == error)
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_MEDIUM_ERROR;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_UNRECOVERED_READ_ERROR;
|
|
}
|
|
error = kStatus_USB_InvalidRequest;
|
|
}
|
|
else if (mscCheckEvent->hostExpectedDataLength == mscCheckEvent->deviceExpectedDataLength)
|
|
{ /*case 6*,device intends to send dCBWDataTransferLength excepted by the host*/
|
|
mscHandle->g_mscCsw->dataResidue = 0;
|
|
if (ufi->thirteenCase.lbaSendRecvSelect == 1)
|
|
{
|
|
error = USB_DeviceMscLbaTransfer(mscHandle, USB_IN, &mscCheckEvent->lbaInformation);
|
|
}
|
|
else
|
|
{
|
|
error = USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, mscCheckEvent->buffer,
|
|
mscCheckEvent->deviceExpectedDataLength);
|
|
}
|
|
|
|
if (kStatus_USB_Success == error)
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_MEDIUM_ERROR;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_UNRECOVERED_READ_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{ /*case 7, device intends to send more data than the host indicated*/
|
|
mscHandle->g_mscCsw->dataResidue = 0;
|
|
|
|
if (ufi->thirteenCase.lbaSendRecvSelect == 1)
|
|
{
|
|
mscCheckEvent->lbaInformation.transferNumber =
|
|
mscCheckEvent->hostExpectedDataLength / mscHandle->lengthOfEachLba;
|
|
mscHandle->g_mscCsw->dataResidue =
|
|
mscCheckEvent->hostExpectedDataLength -
|
|
mscCheckEvent->lbaInformation.transferNumber * mscHandle->lengthOfEachLba;
|
|
error = USB_DeviceMscLbaTransfer(mscHandle, USB_IN, &mscCheckEvent->lbaInformation);
|
|
}
|
|
else
|
|
{
|
|
error = USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, mscCheckEvent->buffer,
|
|
mscCheckEvent->hostExpectedDataLength);
|
|
}
|
|
|
|
if (kStatus_USB_Success == error)
|
|
{
|
|
if (ufi->thirteenCase.lbaSendRecvSelect == 1)
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_PHASE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_MEDIUM_ERROR;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_UNRECOVERED_READ_ERROR;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*case 8, device intends to receive data from the host*/
|
|
mscHandle->g_mscCsw->dataResidue = mscCheckEvent->hostExpectedDataLength;
|
|
error = USB_DeviceSendRequest(mscHandle->handle, mscHandle->bulkInEndpoint, mscCheckEvent->buffer, 0);
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_PHASE_ERROR;
|
|
error = kStatus_USB_InvalidRequest;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*Host expects to send data to the device*/
|
|
if (0 == mscCheckEvent->deviceExpectedDataLength)
|
|
{ /*case 9,Device intends to transfer no data*/
|
|
USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkOutEndpoint);
|
|
mscHandle->g_mscCsw->dataResidue = mscCheckEvent->hostExpectedDataLength;
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
mscHandle->outEndpointStallFlag = 1;
|
|
error = kStatus_USB_InvalidRequest;
|
|
}
|
|
else if (mscCheckEvent->deviceExpectedDirection)
|
|
{ /*case 10,Device intends to send data to the host*/
|
|
USB_DeviceStallEndpoint(mscHandle->handle, mscHandle->bulkOutEndpoint);
|
|
mscHandle->g_mscCsw->dataResidue = mscCheckEvent->hostExpectedDataLength;
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_PHASE_ERROR;
|
|
mscHandle->outEndpointStallFlag = 1;
|
|
error = kStatus_USB_InvalidRequest;
|
|
}
|
|
else
|
|
{
|
|
if (mscCheckEvent->hostExpectedDataLength > mscCheckEvent->deviceExpectedDataLength)
|
|
{ /*case 11, device intends to process less than the amount of data that the host indicated*/
|
|
mscHandle->g_mscCsw->dataResidue =
|
|
mscCheckEvent->hostExpectedDataLength - mscCheckEvent->deviceExpectedDataLength;
|
|
|
|
if (ufi->thirteenCase.lbaSendRecvSelect == 1)
|
|
{
|
|
error = USB_DeviceMscLbaTransfer(mscHandle, USB_OUT, &mscCheckEvent->lbaInformation);
|
|
}
|
|
else
|
|
{
|
|
error = USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, mscCheckEvent->buffer,
|
|
mscCheckEvent->deviceExpectedDataLength);
|
|
}
|
|
|
|
if (kStatus_USB_Success == error)
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_MEDIUM_ERROR;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_WRITE_FAULT;
|
|
}
|
|
error = kStatus_USB_InvalidRequest;
|
|
}
|
|
else if (mscCheckEvent->hostExpectedDataLength == mscCheckEvent->deviceExpectedDataLength)
|
|
{ /*case 12,device intends to process equal to the amount of data that the host indicated*/
|
|
mscHandle->g_mscCsw->dataResidue = 0;
|
|
if (ufi->thirteenCase.lbaSendRecvSelect == 1)
|
|
{
|
|
error = USB_DeviceMscLbaTransfer(mscHandle, USB_OUT, &mscCheckEvent->lbaInformation);
|
|
}
|
|
else
|
|
{
|
|
error = USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, mscCheckEvent->buffer,
|
|
mscCheckEvent->deviceExpectedDataLength);
|
|
}
|
|
if (kStatus_USB_Success == error)
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_MEDIUM_ERROR;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_WRITE_FAULT;
|
|
}
|
|
}
|
|
else
|
|
{ /*case 13,device intends to process more data than the host indicated*/
|
|
mscHandle->g_mscCsw->dataResidue = 0;
|
|
if (ufi->thirteenCase.lbaSendRecvSelect == 1)
|
|
{
|
|
mscCheckEvent->lbaInformation.transferNumber =
|
|
mscCheckEvent->hostExpectedDataLength / mscHandle->lengthOfEachLba;
|
|
mscHandle->g_mscCsw->dataResidue =
|
|
mscCheckEvent->hostExpectedDataLength -
|
|
mscCheckEvent->lbaInformation.transferNumber * mscHandle->lengthOfEachLba;
|
|
error = USB_DeviceMscLbaTransfer(mscHandle, USB_OUT, &mscCheckEvent->lbaInformation);
|
|
}
|
|
else
|
|
{
|
|
error = USB_DeviceRecvRequest(mscHandle->handle, mscHandle->bulkOutEndpoint, mscCheckEvent->buffer,
|
|
mscCheckEvent->hostExpectedDataLength);
|
|
}
|
|
|
|
if (kStatus_USB_Success == error)
|
|
{
|
|
if (ufi->thirteenCase.lbaSendRecvSelect == 1)
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_PHASE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_MEDIUM_ERROR;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_WRITE_FAULT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief request sense command.
|
|
*
|
|
* The REQUEST SENSE command instructs the UFI device to transfer sense data to the host for the specified logical
|
|
*unit.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiRequestSenseCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
ufi->thirteenCase.deviceExpectedDataLength = USB_DEVICE_MSC_UFI_REQ_SENSE_DATA_LENGTH;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = (uint8_t *)ufi->requestSense;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief inquiry command.
|
|
*
|
|
* The INQUIRY command requests that information regarding parameters of the UFI device itself be sent to the host.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiInquiryCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = USB_DEVICE_MSC_UFI_INQUIRY_ALLOCATION_LENGTH;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = (uint8_t *)&g_InquiryInfo;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief read command.
|
|
*
|
|
* The READ(10),READ(12) command requests that the UFI device transfer data to the host.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiReadCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
uint32_t logicalBlockAddress = 0;
|
|
uint32_t lbaTransferLen = 0;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
logicalBlockAddress = ((uint32_t)mscHandle->g_mscCbw->cbwcb[2] << 24U);
|
|
logicalBlockAddress |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[3] << 16U);
|
|
logicalBlockAddress |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[4] << 8U);
|
|
logicalBlockAddress |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[5]);
|
|
|
|
if (mscHandle->g_mscCbw->cbwcb[0] == USB_DEVICE_MSC_READ_10_COMMAND)
|
|
{
|
|
lbaTransferLen = (uint16_t)((uint16_t)mscHandle->g_mscCbw->cbwcb[7] << 8U);
|
|
lbaTransferLen |= (uint16_t)mscHandle->g_mscCbw->cbwcb[8];
|
|
}
|
|
else if (mscHandle->g_mscCbw->cbwcb[0] == USB_DEVICE_MSC_READ_12_COMMAND)
|
|
{
|
|
lbaTransferLen = ((uint32_t)mscHandle->g_mscCbw->cbwcb[6] << 24U);
|
|
lbaTransferLen |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[7] << 16U);
|
|
lbaTransferLen |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[8] << 8U);
|
|
lbaTransferLen |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[9]);
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.deviceExpectedDataLength = mscHandle->lengthOfEachLba * lbaTransferLen;
|
|
ufi->thirteenCase.buffer = NULL;
|
|
|
|
ufi->thirteenCase.lbaSendRecvSelect = 1;
|
|
ufi->thirteenCase.lbaInformation.startingLogicalBlockAddress = logicalBlockAddress;
|
|
ufi->thirteenCase.lbaInformation.transferNumber = lbaTransferLen;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief write command.
|
|
*
|
|
* The WRITE(10),WRITE(12) command requests that the UFI device write the data transferred by the host to the medium.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiWriteCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
uint32_t logicalBlockAddress = 0;
|
|
uint32_t lbaTransferLen = 0;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
logicalBlockAddress = ((uint32_t)mscHandle->g_mscCbw->cbwcb[2] << 24U);
|
|
logicalBlockAddress |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[3] << 16U);
|
|
logicalBlockAddress |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[4] << 8U);
|
|
logicalBlockAddress |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[5]);
|
|
|
|
if (mscHandle->g_mscCbw->cbwcb[0] == USB_DEVICE_MSC_WRITE_10_COMMAND)
|
|
{
|
|
lbaTransferLen = (uint16_t)((uint16_t)mscHandle->g_mscCbw->cbwcb[7] << 8U);
|
|
lbaTransferLen |= (uint16_t)mscHandle->g_mscCbw->cbwcb[8];
|
|
}
|
|
else if (mscHandle->g_mscCbw->cbwcb[0] == USB_DEVICE_MSC_WRITE_12_COMMAND)
|
|
{
|
|
lbaTransferLen = ((uint32_t)mscHandle->g_mscCbw->cbwcb[6] << 24U);
|
|
lbaTransferLen |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[7] << 16U);
|
|
lbaTransferLen |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[8] << 8U);
|
|
lbaTransferLen |= ((uint32_t)mscHandle->g_mscCbw->cbwcb[9]);
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_OUT;
|
|
ufi->thirteenCase.deviceExpectedDataLength = mscHandle->lengthOfEachLba * lbaTransferLen;
|
|
ufi->thirteenCase.buffer = NULL;
|
|
|
|
ufi->thirteenCase.lbaSendRecvSelect = 1;
|
|
ufi->thirteenCase.lbaInformation.startingLogicalBlockAddress = logicalBlockAddress;
|
|
ufi->thirteenCase.lbaInformation.transferNumber = lbaTransferLen;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief test unit ready command.
|
|
*
|
|
* The TEST UNIT READY command provides a means to check if the UFI device is ready.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiTestUnitReadyCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = 0;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = NULL;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief verify command.
|
|
*
|
|
* The VERIFY command requests that the UFI device verify the data on the medium.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiVerifyCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = 0;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = NULL;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief mode sense command.
|
|
*
|
|
* The MODE SENSE command allows the UFI device to report medium or device parameters to the host.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiModeSenseCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = sizeof(g_ModeParametersHeader);
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = (uint8_t *)&g_ModeParametersHeader;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief mode select command.
|
|
*
|
|
* The MODE SELECT command allows the host to specify medium or device parameters to the UFI device.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiModeSelectCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error = kStatus_USB_TransferFailed;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = sizeof(g_ModeParametersHeader);
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_OUT;
|
|
ufi->thirteenCase.buffer = (uint8_t *)&g_ModeParametersHeader;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
|
|
if (mscHandle->g_mscCbw->cbwcb[1] & 0x01U)
|
|
{
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_ILLEGAL_REQUEST;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_INVALID_FIELD_IN_COMMAND_PKT;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief read capacity command.
|
|
*
|
|
* The READ CAPACITIY command allows the host to request capacities of the currently installed medium.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiReadCapacityCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error = kStatus_USB_TransferFailed;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
if (mscHandle->g_mscCbw->cbwcb[0] == USB_DEVICE_MSC_READ_CAPACITY_10_COMMAND)
|
|
{
|
|
ufi->thirteenCase.deviceExpectedDataLength = USB_DEVICE_MSC_UFI_READ_CAPACITY_DATA_LENGTH;
|
|
ufi->thirteenCase.buffer = (uint8_t *)(ufi->readCapacity);
|
|
}
|
|
else
|
|
{
|
|
ufi->thirteenCase.deviceExpectedDataLength = USB_DEVICE_MSC_UFI_READ_CAPACITY16_DATA_LENGTH;
|
|
ufi->thirteenCase.buffer = (uint8_t *)(ufi->readCapacity16);
|
|
}
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief read format capacity command.
|
|
*
|
|
* The READ FORMAT CAPACITIES command allows the host to request a list of the possible capacities that
|
|
* can be formatted on the currently installed medium.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiReadFormatCapacityCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error = kStatus_USB_TransferFailed;
|
|
usb_device_current_max_capacity_descriptor_struct_t currentMaxHead;
|
|
usb_device_formattable_capacity_descriptor_struct_t formattableCapacityHead;
|
|
usb_device_capacity_list_header_struct_t capacityListHead = {{0x00, 0x00, 0x00}, 0x00};
|
|
uint32_t responseSize;
|
|
uint16_t allocationLength;
|
|
uint8_t numFormattableCapDesc;
|
|
uint8_t descriptorCode;
|
|
uint8_t count = 0;
|
|
uint8_t i = 0;
|
|
uint8_t j = 0;
|
|
uint8_t *ptr;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
allocationLength = (uint16_t)((uint8_t)(mscHandle->g_mscCbw->cbwcb[7] << 8U) | mscHandle->g_mscCbw->cbwcb[8]);
|
|
/*reference ufi command spec table-33 Descriptor Code definition*/
|
|
numFormattableCapDesc = (uint8_t)(ufi->formattedDisk ? (mscHandle->implementingDiskDrive ? 0x02 : 0x03) : 0x00);
|
|
|
|
formattableCapacityHead.blockNumber = USB_LONG_TO_BIG_ENDIAN(mscHandle->totalLogicalBlockNumber);
|
|
formattableCapacityHead.blockLength = USB_LONG_TO_BIG_ENDIAN(mscHandle->lengthOfEachLba);
|
|
|
|
descriptorCode =
|
|
(uint8_t)(ufi->formattedDisk ? USB_DEVICE_MSC_UFI_FORMATTED_MEDIA : USB_DEVICE_MSC_UFI_UNFORMATTED_MEDIA);
|
|
capacityListHead.capacityListLength = numFormattableCapDesc * 8;
|
|
currentMaxHead.blockNumber = USB_LONG_TO_BIG_ENDIAN(mscHandle->totalLogicalBlockNumber);
|
|
currentMaxHead.descriptorCodeBlockLength =
|
|
USB_LONG_TO_BIG_ENDIAN(((uint8_t)(descriptorCode << 24U) | mscHandle->lengthOfEachLba));
|
|
|
|
responseSize = 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) * numFormattableCapDesc;
|
|
|
|
if (responseSize > allocationLength)
|
|
{
|
|
responseSize = allocationLength;
|
|
}
|
|
if (sizeof(ufi->formatCapacityData) < responseSize)
|
|
{
|
|
}
|
|
|
|
ptr = (uint8_t *)&capacityListHead;
|
|
for (count = 0; count < sizeof(capacityListHead); count++)
|
|
{
|
|
ufi->formatCapacityData[count] = ptr[i++];
|
|
}
|
|
ptr = (uint8_t *)¤tMaxHead;
|
|
i = 0;
|
|
for (; i < sizeof(currentMaxHead); count++)
|
|
{
|
|
ufi->formatCapacityData[count] = ptr[i++];
|
|
}
|
|
|
|
if (ufi->formattedDisk)
|
|
{
|
|
for (i = 0; i < numFormattableCapDesc; i++)
|
|
{
|
|
ptr = (uint8_t *)&formattableCapacityHead;
|
|
|
|
for (; count < sizeof(formattableCapacityHead); count++)
|
|
{
|
|
ufi->formatCapacityData[count] = ptr[j++];
|
|
}
|
|
}
|
|
}
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = responseSize;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = ufi->formatCapacityData;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief format unit command.
|
|
*
|
|
* The Host sends the FORMAT UNIT command to physically format one track of a diskette according to the selected
|
|
*options.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiFormatUnitCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = 0;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = NULL;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
|
|
if (mscHandle->g_mscCsw->cswStatus != USB_DEVICE_MSC_PHASE_ERROR)
|
|
{
|
|
if ((mscHandle->g_mscCbw->cbwcb[1] & 0x1FU) == 0x17)
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_PASSED;
|
|
}
|
|
else
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_ILLEGAL_REQUEST;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_INVALID_FIELD_IN_COMMAND_PKT;
|
|
}
|
|
}
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief prevent allow medium command.
|
|
*
|
|
* This command tells the UFI device to enable or disable the removal of the medium in the logical unit.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiPreventAllowMediumCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
uint8_t prevent;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
prevent = mscHandle->g_mscCbw->cbwcb[4] & USB_DEVICE_MSC_UFI_PREVENT_ALLOW_REMOVAL_MASK;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = 0;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = NULL;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
|
|
if (mscHandle->g_mscCsw->cswStatus != USB_DEVICE_MSC_PHASE_ERROR)
|
|
{
|
|
if ((!USB_DEVICE_CONFIG_MSC_SUPPORT_DISK_LOCKING_MECHANISM && prevent))
|
|
{
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_ILLEGAL_REQUEST;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_INVALID_FIELD_IN_COMMAND_PKT;
|
|
}
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief send diagnostic command.
|
|
*
|
|
* The SEND DIAGNOSTIC command requests the UFI device to do a reset or perform a self-test.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiSendDiagnosticCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = 0;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = NULL;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief start stop unit command.
|
|
*
|
|
* The START-STOP UNIT command instructs the UFI device to enable or disable media access operations.
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiStartStopUnitCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
usb_status_t error;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
ufi->thirteenCase.deviceExpectedDataLength = 0;
|
|
ufi->thirteenCase.deviceExpectedDirection = USB_IN;
|
|
ufi->thirteenCase.buffer = NULL;
|
|
ufi->thirteenCase.lbaSendRecvSelect = 0;
|
|
|
|
error = USB_DeviceMscUfiThirteenCasesCheck(mscHandle);
|
|
|
|
return error;
|
|
}
|
|
|
|
/*!
|
|
* @brief unsupported command.
|
|
*
|
|
* Handle unsupported command .
|
|
*
|
|
* @param handle The device msc class handle.
|
|
*
|
|
*@return A USB error code or kStatus_USB_Success.
|
|
*/
|
|
usb_status_t USB_DeviceMscUfiUnsupportCommand(usb_device_msc_struct_t *mscHandle)
|
|
{
|
|
usb_device_msc_ufi_struct_t *ufi = NULL;
|
|
|
|
ufi = &mscHandle->g_mscUfi;
|
|
|
|
mscHandle->g_mscCsw->dataResidue = 0;
|
|
mscHandle->g_mscCsw->cswStatus = USB_DEVICE_MSC_COMMAND_FAILED;
|
|
|
|
ufi->requestSense->senseKey = USB_DEVICE_MSC_UFI_ILLEGAL_REQUEST;
|
|
ufi->requestSense->additionalSenseCode = USB_DEVICE_MSC_UFI_INVALID_COMMAND_OPCODE;
|
|
ufi->requestSense->additionalSenseQualifer = USB_DEVICE_MSC_UFI_NO_SENSE;
|
|
|
|
return kStatus_USB_Success;
|
|
}
|
|
|
|
#endif
|