Ejemplo n.º 1
0
//------------------------------------------------------------------------------
//! \brief  Performs a TEST UNIT READY COMMAND command.
//! \param  lun          Pointer to the LUN affected by the command
//! \return Operation result code (SUCCESS, ERROR, INCOMPLETE or PARAMETER)
//! \see    MSDLun
//------------------------------------------------------------------------------
static unsigned char SBC_TestUnitReady(MSDLun *lun)
{
    unsigned char result = MSDD_STATUS_ERROR;

    // Check current media state
    switch(lun->media->state) {
    //-------------------
    case MED_STATE_READY:
    //-------------------
        // Nothing to do
        TRACE_INFO_WP("Rdy ");
        result = MSDD_STATUS_SUCCESS;
        break;

    //------------------
    case MED_STATE_BUSY:
    //------------------
        TRACE_INFO_WP("Bsy ");
        SBC_UpdateSenseData(&(lun->requestSenseData),
                            SBC_SENSE_KEY_NOT_READY,
                            0,
                            0);
        break;

    //------
    default:
    //------
        TRACE_INFO_WP("? ");
        SBC_UpdateSenseData(&(lun->requestSenseData),
                            SBC_SENSE_KEY_NOT_READY,
                            SBC_ASC_MEDIUM_NOT_PRESENT,
                            0);
        break;
    }

    return result;
}
Ejemplo n.º 2
0
//-----------------------------------------------------------------------------
/// Processes the latest command received by the %device.
/// \param  pMsdDriver Pointer to a MSDDriver instance
/// \return 1 if the command has been completed, false otherwise.
//-----------------------------------------------------------------------------
static unsigned char MSDD_ProcessCommand(MSDDriver * pMsdDriver)
{
    unsigned char   status;
    MSDCommandState *commandState = &(pMsdDriver->commandState);
    MSCbw           *cbw = &(commandState->cbw);
    MSCsw           *csw = &(commandState->csw);
    MSDLun          *lun = &(pMsdDriver->luns[(unsigned char) cbw->bCBWLUN]);
    unsigned char   isCommandComplete = 0;

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

        TRACE_WARNING(
            "MSDD_ProcessCommand: LUN %d not exist\n\r", cbw->bCBWLUN);
        status = MSDD_STATUS_ERROR;
    }
    else {

        // Process command
        if (pMsdDriver->maxLun > 0) {

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

        status = SBC_ProcessCommand(lun, commandState);
    }

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

        TRACE_WARNING(
            "MSDD_ProcessCommand: Unknown cmd 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
            // MSDD_Halt(MSDD_CASE_STALL_OUT);
            commandState->postprocess = MSDD_CASE_STALL_OUT;
            TRACE_INFO_WP("StaOUT ");
        }
        else {

            // Stall the IN endpoint : device to host
            // MSDD_Halt(MSDD_CASE_STALL_IN);
            commandState->postprocess = MSDD_CASE_STALL_IN;
            TRACE_INFO_WP("StaIN ");
        }
    }
    else if (status == MSDD_STATUS_ERROR) {

        TRACE_WARNING("MSD_ProcessCommand: Cmd %x fail\n\r",
                   ((SBCCommand*)commandState->cbw.pCommand)->bOperationCode);

        // Update sense data
        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 if (status == MSDD_STATUS_RW) {

        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 == MSDD_STATUS_SUCCESS) {

            isCommandComplete = 1;
        }
    }

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

        TRACE_INFO_WP("Cplt ");

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

            csw->dCSWDataResidue += commandState->length;

            // STALL the endpoint waiting for data
            if ((cbw->bmCBWFlags & MSD_CBW_DEVICE_TO_HOST) == 0) {

                // Stall the OUT endpoint : host to device
                // MSDD_Halt(MSDD_CASE_STALL_OUT);
                commandState->postprocess = MSDD_CASE_STALL_OUT;
                TRACE_INFO_WP("StaOUT ");
            }
            else {

                // Stall the IN endpoint : device to host
                // MSDD_Halt(MSDD_CASE_STALL_IN);
                commandState->postprocess = MSDD_CASE_STALL_IN;
                TRACE_INFO_WP("StaIN ");
            }
        }

        // Reset command state
        commandState->state = 0;
    }

    return isCommandComplete;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
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;
}