Example #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;
    }
}
Example #2
0
//------------------------------------------------------------------------------
//! \brief  Performs a MODE SENSE (6) command.
//!
//!         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_ModeSense6(MSDCommandState *commandState)
{
    unsigned char      result = MSDD_STATUS_INCOMPLETE;
    unsigned char      status;
    MSDTransfer     *transfer = &(commandState->transfer);

    // Check if mode page is supported
    if (((SBCCommand *) commandState->cbw.pCommand)->modeSense6.bPageCode
        != SBC_PAGE_RETURN_ALL) {

        return MSDD_STATUS_PARAMETER;
    }

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

        commandState->state = SBC_STATE_WRITE;
    }

    // Check current command state
    switch (commandState->state) {
    //-------------------
    case SBC_STATE_WRITE:
    //-------------------
        // Start transfer
        status = MSDD_Write((void *) &modeParameterHeader6,
                            commandState->length,
                            (TransferCallback) MSDDriver_Callback,
                            (void *) transfer);

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

            TRACE_WARNING(
                "SPC_ModeSense6: Cannot start data transfer\n\r");
            result = MSDD_STATUS_ERROR;
        }
        else {

            // Proceed to 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 terminate command
            transfer->semaphore--;

            if (transfer->status != USBD_STATUS_SUCCESS) {

                TRACE_WARNING(
                    "SPC_ModeSense6: Data transfer failed\n\r");
                result = MSDD_STATUS_ERROR;
            }
            else {

                result = MSDD_STATUS_SUCCESS;
            }

            // Update length field
            commandState->length -= transfer->transferred;

        }
        break;
    }

    return result;
}
Example #3
0
//------------------------------------------------------------------------------
//! \brief  Performs a REQUEST SENSE command.
//!
//!         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_RequestSense(MSDLun               *lun,
                                      MSDCommandState *commandState)
{
    unsigned char result = MSDD_STATUS_INCOMPLETE;
    unsigned char status;
    MSDTransfer *transfer = &(commandState->transfer);

    // Check if requested length is zero
    if (commandState->length == 0) {

        // Nothing to do
        result = MSDD_STATUS_SUCCESS;
    }
    // Initialize command state if needed
    else if (commandState->state == 0) {

        commandState->state = SBC_STATE_WRITE;
    }

    // Identify current command state
    switch (commandState->state) {
    //-------------------
    case SBC_STATE_WRITE:
    //-------------------
        // Start transfer
        status = MSDD_Write(&(lun->requestSenseData),
                            commandState->length,
                            (TransferCallback) MSDDriver_Callback,
                            (void *) transfer);

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

            TRACE_WARNING(
                "RBC_RequestSense: Cannot start sending data\n\r");
            result = MSDD_STATUS_ERROR;
        }
        else {

            // Change state
            commandState->state = SBC_STATE_WAIT_WRITE;
        }
        break;

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

            // Take semaphore and finish command
            transfer->semaphore--;

            if (transfer->status != USBD_STATUS_SUCCESS) {

                result = MSDD_STATUS_ERROR;
            }
            else {

                result = MSDD_STATUS_SUCCESS;
            }

            // Update length
            commandState->length -= transfer->transferred;
        }
        break;
    }

    return result;
}
Example #4
0
//------------------------------------------------------------------------------
//! \brief  Handles an INQUIRY command.
//!
//!         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_Inquiry(MSDLun               *lun,
                                 MSDCommandState *commandState)
{
    unsigned char  result = MSDD_STATUS_INCOMPLETE;
    unsigned char  status;
    MSDTransfer *transfer = &(commandState->transfer);

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

        // Nothing to do
        result = MSDD_STATUS_SUCCESS;
    }
    // Initialize command state if needed
    else if (commandState->state == 0) {

        commandState->state = SBC_STATE_WRITE;

        // Change additional length field of inquiry data
        lun->inquiryData->bAdditionalLength
            = (unsigned char) (commandState->length - 5);
    }

    // Identify current command state
    switch (commandState->state) {
    //-------------------
    case SBC_STATE_WRITE:
    //-------------------
        // Start write operation
        status = MSDD_Write((void *) lun->inquiryData,
                            commandState->length,
                            (TransferCallback) MSDDriver_Callback,
                            (void *) transfer);

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

            TRACE_WARNING(
                "SPC_Inquiry: Cannot start sending data\n\r");
            result = MSDD_STATUS_ERROR;
        }
        else {

            // Proceed to next state
            TRACE_INFO_WP("Sending ");
            commandState->state = SBC_STATE_WAIT_WRITE;
        }
        break;

    //------------------------
    case SBC_STATE_WAIT_WRITE:
    //------------------------
        // Check the semaphore value
        if (transfer->semaphore > 0) {

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

            if (transfer->status != USBD_STATUS_SUCCESS) {

                TRACE_WARNING(
                    "SPC_Inquiry: Data transfer failed\n\r");
                result = MSDD_STATUS_ERROR;
            }
            else {

                TRACE_INFO_WP("Sent ");
                result = MSDD_STATUS_SUCCESS;
            }

            // Update length field
            commandState->length -= transfer->transferred;
        }
        break;
    }

    return result;
}
Example #5
0
//------------------------------------------------------------------------------
//! \brief  Performs a READ CAPACITY (10) command.
//!
//!         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_ReadCapacity10(MSDLun               *lun,
                                        MSDCommandState *commandState)
{
    unsigned char result = MSDD_STATUS_INCOMPLETE;
    unsigned char status;
    MSDTransfer *transfer = &(commandState->transfer);

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

        commandState->state = SBC_STATE_WRITE;
    }

    // Identify current command state
    switch (commandState->state) {
    //-------------------
    case SBC_STATE_WRITE:
    //-------------------
        // Start the write operation
        status = MSDD_Write(&(lun->readCapacityData),
                            commandState->length,
                            (TransferCallback) MSDDriver_Callback,
                            (void *) transfer);

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

            TRACE_WARNING(
                "RBC_ReadCapacity: Cannot start sending data\n\r");
            result = MSDD_STATUS_ERROR;
        }
        else {

            // Proceed to next command state
            TRACE_INFO_WP("Sending ");
            commandState->state = SBC_STATE_WAIT_WRITE;
        }
        break;

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

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

            if (transfer->status != USBD_STATUS_SUCCESS) {

                TRACE_WARNING("RBC_ReadCapacity: Cannot send data\n\r");
                result = MSDD_STATUS_ERROR;
            }
            else {

                TRACE_INFO_WP("Sent ");
                result = MSDD_STATUS_SUCCESS;
            }
            commandState->length -= transfer->transferred;
        }
        break;
    }

    return result;
}
Example #6
0
//------------------------------------------------------------------------------
//! \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 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_Read10(MSDLun          *lun,
                                MSDCommandState *commandState)
{
    unsigned char status;
    unsigned char result = MSDD_STATUS_INCOMPLETE;
    SBCRead10 *command = (SBCRead10 *) commandState->cbw.pCommand;
    MSDTransfer *transfer = &(commandState->transfer);

    // 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 length
    if (commandState->length == 0) {

        result = MSDD_STATUS_SUCCESS;
    }
    else {

        // Command state management
        switch (commandState->state) {
        //------------------
        case SBC_STATE_READ:
        //------------------
            // Read one block of data from the media
#if !defined(AT91C_EBI_SDRAM) && !defined(BOARD_USB_UDPHS) 
            status = LUN_Read(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 != LUN_STATUS_SUCCESS) {

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

                // Move to next command state
                commandState->state = SBC_STATE_WAIT_READ;
            }
            break;

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

                TRACE_INFO_WP("Ok ");

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

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

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

                // Send the block to the host
#if !defined(AT91C_EBI_SDRAM) && !defined(BOARD_USB_UDPHS) 
                status = MSDD_Write((void*)lun->readWriteBuffer,
                                    lun->blockSize,
                                    (TransferCallback) MSDDriver_Callback,
                                    (void *) transfer);
#else

                status = MSDD_Write((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_Read10: Failed to start to send data\n\r");
                    SBC_UpdateSenseData(&(lun->requestSenseData),
                                        SBC_SENSE_KEY_HARDWARE_ERROR,
                                        0,
                                        0);
                    result = MSDD_STATUS_ERROR;
                }
                else {

                    TRACE_INFO_WP("Sending ");

                    // Move to next command state
                    commandState->state = SBC_STATE_WAIT_WRITE;
                }
            }
            break;

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

                TRACE_INFO_WP("Sent ");

                // 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_Read10: Failed to send data\n\r");
                SBC_UpdateSenseData(&(lun->requestSenseData),
                                    SBC_SENSE_KEY_HARDWARE_ERROR,
                                    0,
                                    0);
                result = MSDD_STATUS_ERROR;
            }
            else {
                TRACE_INFO_WP("Next ");

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

                // 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;
}