📄 sbc_methods.c
字号:
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support - ROUSSET -
* ----------------------------------------------------------------------------
* Copyright (c) 2006, Atmel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaiimer below.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the disclaimer below in the documentation and/or
* other materials provided with the distribution.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/*
$Id: sbc_methods.c 198 2006-10-30 10:01:09Z jjoannic $
*/
//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------
#include "core/common.h"
#include "core/device.h"
#include "core/board.h"
#include "core/trace.h"
#include "core/usb.h"
#include "core/standard.h"
#include "msd.h"
#include "media.h"
#include "sbc.h"
#include "lun.h"
#include "bot_driver.h"
#include "sbc_methods.h"
//------------------------------------------------------------------------------
// Global variables
//------------------------------------------------------------------------------
//! \brief Header for the mode pages data
//! \see S_sbc_mode_parameter_header_6
static const S_sbc_mode_parameter_header_6 sModeParameterHeader6 = {
sizeof(S_sbc_mode_parameter_header_6) - 1, //!< Length of mode page data is 0x03
SBC_MEDIUM_TYPE_DIRECT_ACCESS_BLOCK_DEVICE, //!< Direct-access block device
0, //!< Reserved bits
false, //!< DPO/FUA not supported
0, //!< Reserved bits
false, //!< Medium is not write-protected
0 //!< No block descriptor
};
//------------------------------------------------------------------------------
// Internal functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//! \brief Performs a WRITE (10) command on the specified LUN.
//!
//! The data to write is first received from the USB host and then
//! actually written on the media.
//! This function operates asynchronously and must be called multiple
//! times to complete. A result code of BOT_STATUS_INCOMPLETE indicates
//! that at least another call of the method is necessary.
//! \param pUsb Pointer to a S_usb instance
//! \param pLun Pointer to the LUN affected by the command
//! \param pCommandState Current state of the command
//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
//! \see S_usb
//! \see S_lun
//! \see S_bot_command_state
//------------------------------------------------------------------------------
static unsigned char SBC_Write10(const S_usb *pUsb,
S_lun *pLun,
S_bot_command_state *pCommandState)
{
unsigned char bStatus;
unsigned char bResult = BOT_STATUS_INCOMPLETE;
S_bot_transfer *pTransfer = &(pCommandState->sTransfer);
S_sbc_write_10 *pCommand = (S_sbc_write_10 *) pCommandState->sCbw.pCommand;
// Init command state
if (pCommandState->bState == 0) {
pCommandState->bState = SBC_STATE_READ;
}
// Convert pLength from bytes to blocks
pCommandState->dLength /= pLun->dBlockSize;
// Check if pLength equals 0
if (pCommandState->dLength == 0) {
TRACE_DEBUG_M("End ");
bResult = BOT_STATUS_SUCCESS;
}
else {
// Current command status
switch (pCommandState->bState) {
//------------------
case SBC_STATE_READ:
//------------------
TRACE_DEBUG_M("Receive ");
// Read one block of data sent by the host
bStatus = USB_Read(pUsb,
BOT_EPT_BULK_OUT,
pLun->pReadWriteBuffer,
pLun->dBlockSize,
(Callback_f) BOT_Callback,
(void *) pTransfer);
// Check operation result code
if (bStatus != USB_STATUS_SUCCESS) {
TRACE_WARNING("W: RBC_Write10: Failed to start receiving data\n\r");
SBC_UpdateSenseData(&(pLun->sRequestSenseData),
SBC_SENSE_KEY_HARDWARE_ERROR,
0,
0);
bResult = BOT_STATUS_ERROR;
}
else {
// Prepare next device state
pCommandState->bState = SBC_STATE_WAIT_READ;
}
break;
//-----------------------
case SBC_STATE_WAIT_READ:
//-----------------------
TRACE_DEBUG_M("Wait ");
// Check semaphore
if (pTransfer->bSemaphore > 0) {
pTransfer->bSemaphore--;
pCommandState->bState = SBC_STATE_WRITE;
}
break;
//-------------------
case SBC_STATE_WRITE:
//-------------------
// Check the result code of the read operation
if (pTransfer->bStatus != USB_STATUS_SUCCESS) {
TRACE_WARNING("W: RBC_Write10: Failed to received data\n\r");
SBC_UpdateSenseData(&(pLun->sRequestSenseData),
SBC_SENSE_KEY_HARDWARE_ERROR,
0,
0);
bResult = BOT_STATUS_ERROR;
}
else {
// Write the block to the media
bStatus = LUN_Write(pLun,
DWORDB(pCommand->pLogicalBlockAddress),
pLun->pReadWriteBuffer,
1,
(Callback_f) BOT_Callback,
(void *) pTransfer);
// Check operation result code
if (bStatus != USB_STATUS_SUCCESS) {
TRACE_WARNING("W: RBC_Write10: Failed to start media write\n\r");
SBC_UpdateSenseData(&(pLun->sRequestSenseData),
SBC_SENSE_KEY_NOT_READY,
0,
0);
bResult = BOT_STATUS_ERROR;
}
else {
// Prepare next state
pCommandState->bState = SBC_STATE_WAIT_WRITE;
}
}
break;
//------------------------
case SBC_STATE_WAIT_WRITE:
//------------------------
TRACE_DEBUG_M("Wait ");
// Check semaphore value
if (pTransfer->bSemaphore > 0) {
// Take semaphore and move to next state
pTransfer->bSemaphore--;
pCommandState->bState = SBC_STATE_NEXT_BLOCK;
}
break;
//------------------------
case SBC_STATE_NEXT_BLOCK:
//------------------------
// Check operation result code
if (pTransfer->bStatus != USB_STATUS_SUCCESS) {
TRACE_WARNING("W: RBC_Write10: Failed to write media\n\r");
SBC_UpdateSenseData(&(pLun->sRequestSenseData),
SBC_SENSE_KEY_RECOVERED_ERROR,
SBC_ASC_TOO_MUCH_WRITE_DATA,
0);
bResult = BOT_STATUS_ERROR;
}
else {
// Update transfer length and block address
pCommandState->dLength--;
STORE_DWORDB(DWORDB(pCommand->pLogicalBlockAddress) + 1,
pCommand->pLogicalBlockAddress);
// Check if transfer is finished
if (pCommandState->dLength == 0) {
bResult = BOT_STATUS_SUCCESS;
}
else {
pCommandState->bState = SBC_STATE_READ;
}
}
break;
}
}
// Convert dLength from blocks to bytes
pCommandState->dLength *= pLun->dBlockSize;
return bResult;
}
//------------------------------------------------------------------------------
//! \brief Performs a READ (10) command on specified LUN.
//!
//! The data is first read from the media and then sent to the USB host.
//! This function operates asynchronously and must be called multiple
//! times to complete. A result code of BOT_STATUS_INCOMPLETE indicates
//! that at least another call of the method is necessary.
//! \param pUsb Pointer to a S_usb instance
//! \param pLun Pointer to the LUN affected by the command
//! \param pCommandState Current state of the command
//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
//! \see S_usb
//! \see S_lun
//! \see S_bot_command_state
//------------------------------------------------------------------------------
static unsigned char SBC_Read10(const S_usb *pUsb,
S_lun *pLun,
S_bot_command_state *pCommandState)
{
unsigned char bStatus;
unsigned char bResult = BOT_STATUS_INCOMPLETE;
S_sbc_read_10 *pCommand = (S_sbc_read_10 *) pCommandState->sCbw.pCommand;
S_bot_transfer *pTransfer = &(pCommandState->sTransfer);
// Init command state
if (pCommandState->bState == 0) {
pCommandState->bState = SBC_STATE_READ;
}
// Convert dLength from bytes to blocks
pCommandState->dLength /= pLun->dBlockSize;
// Check length
if (pCommandState->dLength == 0) {
bResult = BOT_STATUS_SUCCESS;
}
else {
// Command state management
switch (pCommandState->bState) {
//------------------
case SBC_STATE_READ:
//------------------
// Read one block of data from the media
bStatus = LUN_Read(pLun,
DWORDB(pCommand->pLogicalBlockAddress),
pLun->pReadWriteBuffer,
1,
(Callback_f) BOT_Callback,
(void *) pTransfer);
// Check operation result code
if (bStatus != LUN_STATUS_SUCCESS) {
TRACE_WARNING("W: RBC_Read10: Failed to start reading media\n\r");
SBC_UpdateSenseData(&(pLun->sRequestSenseData),
SBC_SENSE_KEY_NOT_READY,
SBC_ASC_LOGICAL_UNIT_NOT_READY,
0);
bResult = BOT_STATUS_ERROR;
}
else {
// Move to next command state
pCommandState->bState = SBC_STATE_WAIT_READ;
}
break;
//-----------------------
case SBC_STATE_WAIT_READ:
//-----------------------
// Check semaphore value
if (pTransfer->bSemaphore > 0) {
TRACE_DEBUG_M("Ok ");
// Take semaphore and move to next state
pTransfer->bSemaphore--;
pCommandState->bState = SBC_STATE_WRITE;
}
break;
//-------------------
case SBC_STATE_WRITE:
//-------------------
// Check the operation result code
if (pTransfer->bStatus != USB_STATUS_SUCCESS) {
TRACE_WARNING("W: RBC_Read10: Failed to read media\n\r");
SBC_UpdateSenseData(&(pLun->sRequestSenseData),
SBC_SENSE_KEY_RECOVERED_ERROR,
SBC_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE,
0);
bResult = BOT_STATUS_ERROR;
}
else {
// Send the block to the host
bStatus = USB_Write(pUsb,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -