Пример #1
0
//-----------------------------------------------------------------------------
/// State machine for the MSD %device driver
/// \param  pMsdDriver Pointer to a MSDDriver instance
//-----------------------------------------------------------------------------
void MSDD_StateMachine(MSDDriver * pMsdDriver)
{
    MSDCommandState *commandState = &(pMsdDriver->commandState);
    MSCbw           *cbw = &(commandState->cbw);
    MSCsw           *csw = &(commandState->csw);
    MSDTransfer     *transfer = &(commandState->transfer);
    unsigned char   status;

    // Identify current driver state
    switch (pMsdDriver->state) {
    //----------------------
    case MSDD_STATE_READ_CBW:
    //----------------------
        // Start the CBW read operation
        transfer->semaphore = 0;
        status = MSDD_Read(cbw,
                           MSD_CBW_SIZE,
                           (TransferCallback) MSDDriver_Callback,
                           (void *) transfer);

        // Check operation result code
        if (status == USBD_STATUS_SUCCESS) {

            // If the command was successful, wait for transfer
            pMsdDriver->state = MSDD_STATE_WAIT_CBW;
        }
        break;

    //----------------------
    case MSDD_STATE_WAIT_CBW:
    //----------------------
        // Check transfer semaphore
        if (transfer->semaphore > 0) {

            // Take semaphore and terminate transfer
            transfer->semaphore--;

            // Check if transfer was successful
            if (transfer->status == USBD_STATUS_SUCCESS) {

                TRACE_INFO_WP("------------------------------\n\r");

                // Process received command
                pMsdDriver->state = MSDD_STATE_PROCESS_CBW;
            }
            else if (transfer->status == USBD_STATUS_RESET) {

                TRACE_INFO("MSDD_StateMachine: EP resetted\n\r");
                pMsdDriver->state = MSDD_STATE_READ_CBW;
            }
            else {

                TRACE_WARNING(
                    "MSDD_StateMachine: Failed to read CBW\n\r");
                pMsdDriver->state = MSDD_STATE_READ_CBW;
            }
        }
        break;

    //-------------------------
    case MSDD_STATE_PROCESS_CBW:
    //-------------------------
        // Check if this is a new command
        if (commandState->state == 0) {

            // Copy the CBW tag
            csw->dCSWTag = cbw->dCBWTag;

            // Check that the CBW is 31 bytes long
            if ((transfer->transferred != MSD_CBW_SIZE) ||
                (transfer->remaining != 0)) {

                TRACE_WARNING(
                    "MSDD_StateMachine: Invalid CBW (len %d)\n\r",
                    (int)transfer->transferred);

                // Wait for a reset recovery
                pMsdDriver->waitResetRecovery = 1;

                // Halt the Bulk-IN and Bulk-OUT pipes
                MSDD_Halt(MSDD_CASE_STALL_OUT | MSDD_CASE_STALL_IN);

                csw->bCSWStatus = MSD_CSW_COMMAND_FAILED;
                pMsdDriver->state = MSDD_STATE_READ_CBW;

            }
            // Check the CBW Signature
            else if (cbw->dCBWSignature != MSD_CBW_SIGNATURE) {

                TRACE_WARNING(
                    "MSD_BOTStateMachine: Invalid CBW (Bad signature)\n\r");

                // Wait for a reset recovery
                pMsdDriver->waitResetRecovery = 1;

                // Halt the Bulk-IN and Bulk-OUT pipes
                MSDD_Halt(MSDD_CASE_STALL_OUT | MSDD_CASE_STALL_IN);

                csw->bCSWStatus = MSD_CSW_COMMAND_FAILED;
                pMsdDriver->state = MSDD_STATE_READ_CBW;
            }
            else {

                // Pre-process command
                MSDD_PreProcessCommand(pMsdDriver);
            }
        }

        // Process command
        if (csw->bCSWStatus == MSDD_STATUS_SUCCESS) {

            if (MSDD_ProcessCommand(pMsdDriver)) {

                // Post-process command if it is finished
                if (MSDD_PostProcessCommand(pMsdDriver)) {

                    TRACE_INFO_WP("WaitHALT ");
                    pMsdDriver->state = MSDD_STATE_WAIT_HALT;
                }
                else {

                    pMsdDriver->state = MSDD_STATE_SEND_CSW;
                }
            }
            TRACE_INFO_WP("\n\r");
        }

        break;

    //----------------------
    case MSDD_STATE_SEND_CSW:
    //----------------------
        // Set signature
        csw->dCSWSignature = MSD_CSW_SIGNATURE;

        // Start the CSW write operation
        status = MSDD_Write(csw,
                            MSD_CSW_SIZE,
                            (TransferCallback) MSDDriver_Callback,
                            (void *) transfer);

        // Check operation result code
        if (status == USBD_STATUS_SUCCESS) {

            TRACE_INFO_WP("SendCSW ");

            // Wait for end of transfer
            pMsdDriver->state = MSDD_STATE_WAIT_CSW;
        }
        break;

    //----------------------
    case MSDD_STATE_WAIT_CSW:
    //----------------------
        // Check transfer semaphore
        if (transfer->semaphore > 0) {

            // Take semaphore and terminate transfer
            transfer->semaphore--;

            // Check if transfer was successful
            if (transfer->status == USBD_STATUS_RESET) {

                TRACE_INFO("MSDD_StateMachine: EP resetted\n\r");
            }
            else if (transfer->status == USBD_STATUS_ABORTED) {

                TRACE_WARNING(
                    "MSDD_StateMachine: Failed to send CSW\n\r");
            }
            else {

                TRACE_INFO_WP("ok");
            }

            // Read new CBW
            pMsdDriver->state = MSDD_STATE_READ_CBW;
        }
        break;

    //----------------------
    case MSDD_STATE_WAIT_HALT:
    //----------------------
        if (MSDD_IsHalted() == 0) {

            pMsdDriver->state = MSDD_STATE_SEND_CSW;
        }
        break;
    }
}
Пример #2
0
//------------------------------------------------------------------------------
//      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 MSDDriver_STATUS_INCOMPLETE
//!         indicates that at least another call of the method is necessary.
//! \param  lun          Pointer to the LUN affected by the command
//! \param  commandState Current state of the command
//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
//! \see    MSDLun
//! \see    MSDCommandState
//------------------------------------------------------------------------------
static unsigned char SBC_Write10(MSDLun          *lun,
                                 MSDCommandState *commandState)
{
    unsigned char  status;
    unsigned char  result = MSDD_STATUS_INCOMPLETE;
    MSDTransfer *transfer = &(commandState->transfer);
    SBCWrite10 *command = (SBCWrite10 *) commandState->cbw.pCommand;

    // Init command state
    if (commandState->state == 0) {

        commandState->state = SBC_STATE_READ;
    }

#if !defined(AT91C_EBI_SDRAM) && !defined(BOARD_USB_UDPHS) 
    // Convert length from bytes to blocks
    commandState->length /= lun->blockSize;
#endif

    // Check if length equals 0
    if (commandState->length == 0) {

        TRACE_INFO_WP("End ");
        result = MSDD_STATUS_SUCCESS;
    }
    else {

        // Current command status
        switch (commandState->state) {
        //------------------
        case SBC_STATE_READ:
        //------------------
            TRACE_INFO_WP("Receive ");
#if !defined(AT91C_EBI_SDRAM) && !defined(BOARD_USB_UDPHS) 
            // Read one block of data sent by the host
            status = MSDD_Read((void*)lun->readWriteBuffer,
                               lun->blockSize,
                               (TransferCallback) MSDDriver_Callback,
                               (void *) transfer);
#else
            status = MSDD_Read((void*)(lun->media->baseAddress
                                   + lun->baseAddress
                                   + DWORDB(command->pLogicalBlockAddress) * lun->blockSize),
                                commandState->length,
                                (TransferCallback) MSDDriver_Callback,
                                (void *) transfer);
#endif

            // Check operation result code
            if (status != USBD_STATUS_SUCCESS) {

                TRACE_WARNING(
                    "RBC_Write10: Failed to start receiving data\n\r");
                SBC_UpdateSenseData(&(lun->requestSenseData),
                                    SBC_SENSE_KEY_HARDWARE_ERROR,
                                    0,
                                    0);
                result = MSDD_STATUS_ERROR;
            }
            else {

                // Prepare next device state
                commandState->state = SBC_STATE_WAIT_READ;
            }
            break;

        //-----------------------
        case SBC_STATE_WAIT_READ:
        //-----------------------
            TRACE_INFO_WP("Wait ");

            // Check semaphore
            if (transfer->semaphore > 0) {

                transfer->semaphore--;
                commandState->state = SBC_STATE_WRITE;
            }
            break;

        //-------------------
        case SBC_STATE_WRITE:
        //-------------------
            // Check the result code of the read operation
            if (transfer->status != USBD_STATUS_SUCCESS) {

                TRACE_WARNING(
                    "RBC_Write10: Failed to received data\n\r");
                SBC_UpdateSenseData(&(lun->requestSenseData),
                                    SBC_SENSE_KEY_HARDWARE_ERROR,
                                    0,
                                    0);
                result = MSDD_STATUS_ERROR;
            }
            else {

#if !defined(AT91C_EBI_SDRAM) && !defined(BOARD_USB_UDPHS) 
                // Write the block to the media
                status = LUN_Write(lun,
                                    DWORDB(command->pLogicalBlockAddress),
                                    lun->readWriteBuffer,
                                    1,
                                    (TransferCallback) MSDDriver_Callback,
                                    (void *) transfer);
#else
                MSDDriver_Callback(transfer, MED_STATUS_SUCCESS, 0, 0);
                status = LUN_STATUS_SUCCESS;
#endif

                // Check operation result code
                if (status != USBD_STATUS_SUCCESS) {

                    TRACE_WARNING(
                        "RBC_Write10: Failed to start media write\n\r");
                    SBC_UpdateSenseData(&(lun->requestSenseData),
                                        SBC_SENSE_KEY_NOT_READY,
                                        0,
                                        0);
                    result = MSDD_STATUS_ERROR;
                }
                else {

                    // Prepare next state
                    commandState->state = SBC_STATE_WAIT_WRITE;
                }
            }
            break;

        //------------------------
        case SBC_STATE_WAIT_WRITE:
        //------------------------
            TRACE_INFO_WP("Wait ");

            // Check semaphore value
            if (transfer->semaphore > 0) {

                // Take semaphore and move to next state
                transfer->semaphore--;
                commandState->state = SBC_STATE_NEXT_BLOCK;
            }
            break;

        //------------------------
        case SBC_STATE_NEXT_BLOCK:
        //------------------------
            // Check operation result code
            if (transfer->status != USBD_STATUS_SUCCESS) {

                TRACE_WARNING(
                    "RBC_Write10: Failed to write media\n\r");
                SBC_UpdateSenseData(&(lun->requestSenseData),
                                    SBC_SENSE_KEY_RECOVERED_ERROR,
                                    SBC_ASC_TOO_MUCH_WRITE_DATA,
                                    0);
                result = MSDD_STATUS_ERROR;
            }
            else {

                // Update transfer length and block address
#if !defined(AT91C_EBI_SDRAM) && !defined(BOARD_USB_UDPHS) 
                commandState->length--;
#else
                commandState->length = 0;
#endif
                STORE_DWORDB(DWORDB(command->pLogicalBlockAddress) + 1,
                             command->pLogicalBlockAddress);

                // Check if transfer is finished
                if (commandState->length == 0) {

                    result = MSDD_STATUS_SUCCESS;
                }
                else {

                    commandState->state = SBC_STATE_READ;
                }
            }
            break;
        }
    }

#if !defined(AT91C_EBI_SDRAM) && !defined(BOARD_USB_UDPHS) 
    // Convert length from blocks to bytes
    commandState->length *= lun->blockSize;
#endif

    return result;
}