⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 msddriver.c

📁 Atmel的AT91SAM7x256芯片的usb存储的源程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ----------------------------------------------------------------------------
 *         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.
 * ----------------------------------------------------------------------------
 */

//------------------------------------------------------------------------------
//      Includes
//------------------------------------------------------------------------------

#include "MSDDriver.h"
#include "MSDDriverDescriptors.h"
#include "SBCMethods.h"
#include <utility/trace.h>
#include <usb/common/core/USBGenericRequest.h>
#include <usb/common/core/USBFeatureRequest.h>
#include <usb/device/core/USBD.h>
#include <usb/device/core/USBDDriver.h>

//------------------------------------------------------------------------------
//      Structures
//------------------------------------------------------------------------------

//! \brief  MSD driver state variables
//! \see    MSDCommandState
//! \see    S_std_class
//! \see    MSDLun
typedef struct {

    MSDLun *luns;
    MSDCommandState commandState;       //!< State of the currently executing command
    unsigned char maxLun;             //!< Maximum LUN index
    unsigned char state;              //!< Current state of the driver
    unsigned char waitResetRecovery; //!< Indicates if the driver is
                                             //!< waiting for a reset recovery
} MSDDriver;

//------------------------------------------------------------------------------
//         Internal variables
//------------------------------------------------------------------------------

/// Mass storage device driver instance.
static MSDDriver msdDriver;

/// Standard device driver instance.
static USBDDriver usbdDriver;

//------------------------------------------------------------------------------
//      Internal functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//! \brief  Returns the expected transfer length and direction (IN, OUT or don't
//!         care) from the host point-of-view.
//! \param  cbw    Pointer to the CBW to examinate
//! \param  pLength Expected length of command
//! \param  pType   Expected direction of command
//------------------------------------------------------------------------------
static void MSDDriver_GetCommandInformation(MSCbw *cbw,
                                            unsigned int  *length,
                                            unsigned char *type)
{
    // Expected host transfer direction and length
    (*length) = cbw->dCBWDataTransferLength;

    if (*length == 0) {

        (*type) = MSDDriver_NO_TRANSFER;
    }
    else if ((cbw->bmCBWFlags & MSD_CBW_DEVICE_TO_HOST) != 0) {

        (*type) = MSDDriver_DEVICE_TO_HOST;
    }
    else {

        (*type) = MSDDriver_HOST_TO_DEVICE;
    }
}

//------------------------------------------------------------------------------
//! \brief  Pre-processes a command by checking the differences between the
//!         host and device expectations in term of transfer type and length.
//!
//!         Once one of the thirteen cases is identified, the actions to do
//!         during the post-processing phase are stored in the dCase variable
//!         of the command state.
//! \param  pBot Pointer to a S_bot instance
//! \return 1 if the command is supported, false otherwise
//------------------------------------------------------------------------------
static unsigned char MSDDriver_PreProcessCommand()
{
    unsigned int        hostLength;
    unsigned int        deviceLength;
    unsigned char       hostType;
    unsigned char       deviceType;
    unsigned char                isCommandSupported;
    MSDCommandState *commandState = &(msdDriver.commandState);
    MSCsw           *csw = &(commandState->csw);
    MSCbw           *cbw = &(commandState->cbw);
    MSDLun               *lun = &(msdDriver.luns[(unsigned char) cbw->bCBWLUN]);

    // Get information about the command
    // Host-side
    MSDDriver_GetCommandInformation(cbw, &hostLength, &hostType);

    // Device-side
    isCommandSupported = SBC_GetCommandInformation(cbw->pCommand,
                                                   &deviceLength,
                                                   &deviceType,
                                                   lun);

    // Initialize data residue and result status
    csw->dCSWDataResidue = 0;
    csw->bCSWStatus = MSD_CSW_COMMAND_PASSED;

    // Check if the command is supported
    if (isCommandSupported) {

        // Identify the command case
        if(hostType == MSDDriver_NO_TRANSFER) {

            // Case 1  (Hn = Dn)
            if(deviceType == MSDDriver_NO_TRANSFER) {

                trace_LOG(trace_WARNING, "W: Case 1\n\r");
                commandState->postprocess = 0;
                commandState->length = 0;
            }
            else if(deviceType == MSDDriver_DEVICE_TO_HOST) {

                // Case 2  (Hn < Di)
                trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 2\n\r");
                commandState->postprocess = MSDDriver_CASE_PHASE_ERROR;
                commandState->length = 0;
            }
            else { //if(deviceType == MSDDriver_HOST_TO_DEVICE) {

                // Case 3  (Hn < Do)
                trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 3\n\r");
                commandState->postprocess = MSDDriver_CASE_PHASE_ERROR;
                commandState->length = 0;
            }
        }

        // Case 4  (Hi > Dn)
        else if(hostType == MSDDriver_DEVICE_TO_HOST) {

            if(deviceType == MSDDriver_NO_TRANSFER) {

                trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 4\n\r");
                commandState->postprocess = MSDDriver_CASE_STALL_IN;
                commandState->length = 0;
                csw->dCSWDataResidue = hostLength;
            }
            else if(deviceType == MSDDriver_DEVICE_TO_HOST) {

                if(hostLength > deviceLength) {

                    // Case 5  (Hi > Di)
                    trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 5\n\r");
                    commandState->postprocess = MSDDriver_CASE_STALL_IN;
                    commandState->length = deviceLength;
                    csw->dCSWDataResidue = hostLength - deviceLength;
                }
                else if(hostLength == deviceLength) {

                    // Case 6  (Hi = Di)
//                    trace_LOG(trace_WARNING, "W: Case 6\n\r");
                    commandState->postprocess = 0;
                    commandState->length = deviceLength;
                }
                else { //if(hostLength < deviceLength) {

                    // Case 7  (Hi < Di)
                    trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 7\n\r");
                    commandState->postprocess = MSDDriver_CASE_PHASE_ERROR;
                    commandState->length = hostLength;
                }
            }
            else { //if(deviceType == MSDDriver_HOST_TO_DEVICE) {

                // Case 8  (Hi <> Do)
                trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 8\n\r");
                commandState->postprocess = MSDDriver_CASE_STALL_IN | MSDDriver_CASE_PHASE_ERROR;
                commandState->length = 0;
            }
        }
        else if(hostType == MSDDriver_HOST_TO_DEVICE) {

            if(deviceType == MSDDriver_NO_TRANSFER) {

                // Case 9  (Ho > Dn)
                trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 9\n\r");
                commandState->postprocess = MSDDriver_CASE_STALL_OUT;
                commandState->length = 0;
                csw->dCSWDataResidue = hostLength;
            }
            else if(deviceType == MSDDriver_DEVICE_TO_HOST) {

                // Case 10 (Ho <> Di)
                trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 10\n\r");
                commandState->postprocess = MSDDriver_CASE_STALL_OUT | MSDDriver_CASE_PHASE_ERROR;
                commandState->length = 0;
            }
            else { //if(deviceType == MSDDriver_HOST_TO_DEVICE) {

                if(hostLength > deviceLength) {

                    // Case 11 (Ho > Do)
                    trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 11\n\r");
                    commandState->postprocess = MSDDriver_CASE_STALL_OUT;
                    commandState->length = deviceLength;
                    csw->dCSWDataResidue = hostLength - deviceLength;
                }
                else if(hostLength == deviceLength) {

                    // Case 12 (Ho = Do)
                    trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 12\n\r");
                    commandState->postprocess = 0;
                    commandState->length = deviceLength;
                }
                else { //if(hostLength < deviceLength) {

                    // Case 13 (Ho < Do)
                    trace_LOG(trace_WARNING, "W: MSDDriver_PreProcessCommand: Case 13\n\r");
                    commandState->postprocess = MSDDriver_CASE_PHASE_ERROR;
                    commandState->length = hostLength;
                }
            }
        }
    }

    return isCommandSupported;
}

//------------------------------------------------------------------------------
//! \brief  Post-processes a command given the case identified during the
//!         pre-processing step.
//!
//!         Depending on the case, one of the following actions can be done:
//!             - Bulk IN endpoint is stalled
//!             - Bulk OUT endpoint is stalled
//!             - CSW status set to phase error
//! \param  pBot Pointer to a S_bot instance
//------------------------------------------------------------------------------
static void MSDDriver_PostProcessCommand()
{
    MSDCommandState *commandState = &(msdDriver.commandState);
    MSCsw           *csw = &(commandState->csw);

    // STALL Bulk IN endpoint ?
    if ((commandState->postprocess & MSDDriver_CASE_STALL_IN) != 0) {

        trace_LOG(trace_INFO, "StallIn ");
        USBD_Halt(MSDDriverDescriptors_BULKIN);
    }

    // STALL Bulk OUT endpoint ?
    if ((commandState->postprocess & MSDDriver_CASE_STALL_OUT) != 0) {

        trace_LOG(trace_INFO, "StallOut ");
        USBD_Halt(MSDDriverDescriptors_BULKOUT);
    }

    // Set CSW status code to phase error ?
    if ((commandState->postprocess & MSDDriver_CASE_PHASE_ERROR) != 0) {

        trace_LOG(trace_INFO, "PhaseErr ");
        csw->bCSWStatus = MSD_CSW_PHASE_ERROR;
    }
}

//------------------------------------------------------------------------------
//! \brief  Processes the latest command received by the device.
//! \param  pBot Pointer to a S_bot instance
//! \return 1 if the command has been completed, false otherwise.
//------------------------------------------------------------------------------
static unsigned char MSDDriver_ProcessCommand()
{
    unsigned char       status;
    MSDCommandState *commandState = &(msdDriver.commandState);
    MSCbw           *cbw = &(commandState->cbw);
    MSCsw           *csw = &(commandState->csw);
    MSDLun               *lun = &(msdDriver.luns[(unsigned char) cbw->bCBWLUN]);
    unsigned char                isCommandComplete = 0;

    // Check if LUN is valid
    if (cbw->bCBWLUN > msdDriver.maxLun) {

        trace_LOG(trace_WARNING, "W: MSDDriver_ProcessCommand: Requested LUN does not exist\n\r");
        status = MSDDriver_STATUS_ERROR;
    }
    else {

        // Process command
        if (msdDriver.maxLun > 0) {

            trace_LOG(trace_INFO, "LUN%d ", cbw->bCBWLUN);
        }

        status = SBC_ProcessCommand(lun, commandState);
    }

    // Check command result code
    if (status == MSDDriver_STATUS_PARAMETER) {

        trace_LOG(trace_WARNING, "W: MSDDriver_ProcessCommand: Unknown command 0x%02X\n\r",
                      cbw->pCommand[0]);

        // Update sense data
        SBC_UpdateSenseData(&(lun->requestSenseData),
                            SBC_SENSE_KEY_ILLEGAL_REQUEST,
                            SBC_ASC_INVALID_FIELD_IN_CDB,
                            0);

        // Result codes
        csw->bCSWStatus = MSD_CSW_COMMAND_FAILED;
        isCommandComplete = 1;

        // stall the request, IN or OUT
        if (((cbw->bmCBWFlags & MSD_CBW_DEVICE_TO_HOST) == 0)
            && (cbw->dCBWDataTransferLength > 0)) {

            // Stall the OUT endpoint : host to device
            USBD_Halt(MSDDriverDescriptors_BULKOUT);
            trace_LOG(trace_INFO, "StaOUT ");
        }
        else {

            // Stall the IN endpoint : device to host
            USBD_Halt(MSDDriverDescriptors_BULKIN);
            trace_LOG(trace_INFO, "StaIN ");
        }
    }
    else if (status == MSDDriver_STATUS_ERROR) {

        trace_LOG(trace_WARNING, "W: MSD_ProcessCommand: Command failed\n\r");

        // Update sense data
// TODO (jjoannic#1#): Change code
        SBC_UpdateSenseData(&(lun->requestSenseData),
                            SBC_SENSE_KEY_MEDIUM_ERROR,
                            SBC_ASC_INVALID_FIELD_IN_CDB,
                            0);

        // Result codes
        csw->bCSWStatus = MSD_CSW_COMMAND_FAILED;
        isCommandComplete = 1;
    }
    else {

        // Update sense data
        SBC_UpdateSenseData(&(lun->requestSenseData),
                            SBC_SENSE_KEY_NO_SENSE,
                            0,
                            0);

        // Is command complete ?
        if (status == MSDDriver_STATUS_SUCCESS) {

            isCommandComplete = 1;
        }
    }

    // Check if command has been completed
    if (isCommandComplete) {

        trace_LOG(trace_INFO, "Cplt ");

        // Adjust data residue
        if (commandState->length != 0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -