SDSPI_SendCommand
Default mainpageat91libmemoriessdmmcSDSPI_SendCommand
Description Source Call Graph
Start Line: 375
unsigned char SDSPI_SendCommand(SdSpi *pSdSpi, SdSpiCmd *pSdSpiCmd)
{
    AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
    unsigned char CmdToken[6];
    unsigned char *pData;
    unsigned int blockSize;
    unsigned int i;
    unsigned char error;
    unsigned char dataHeader;
    unsigned int dataRetry1 = 100;
    unsigned int dataRetry2 = 100;
    unsigned char crc[2];
    unsigned char crcPrev = 0;
    unsigned char crcPrev2 = 0;

    SANITY_CHECK(pSdSpi);
    SANITY_CHECK(pSpiHw);
    SANITY_CHECK(pCommand);

    CmdToken[0] = pCommand->cmd & 0x3F;
    pData = pCommand->pData;
    blockSize = pCommand->blockSize;

    SDSPI_MakeCmd((unsigned char *)&CmdToken, pCommand->arg);

    // Command is now being executed
    pSdSpi->pCommand = pCommand;
    pCommand->status = SDSPI_STATUS_PENDING;

    // Send the command
    if((pCommand->conTrans == SPI_NEW_TRANSFER) || (blockSize == 0)) {

        for(i = 0; i < 6; i++) {
            error = SDSPI_Write(pSdSpi, &CmdToken[i], 1);
            if (error) {
                TRACE_DEBUG("Error: %d\n\r", error);
                return error;
            }
        }
        // Specific for Cmd12()
        if ((pCommand->cmd & 0x3F) == 12) {
            if( 1 == SDSPI_Wait(pSdSpi, 2) ) {
                TRACE_DEBUG("Pb Send command 12\n\r");
            }
        }
        if (pCommand->pResp) {
            error = SDSPI_GetCmdResp(pSdSpi, pCommand);
            if (error) {
                TRACE_DEBUG("Error: %d\n\r", error);
                return error;
            }
        }
    }

    if( (blockSize > 0) && (pCommand->nbBlock == 0) ) {
        pCommand->nbBlock = 1;
    }

    // For data block operations
    while (pCommand->nbBlock > 0) {

        // If data block size is invalid, return error
        if (blockSize == 0) {
            TRACE_DEBUG("Block Size = 0\n\r");
            return 1;
        }

        // DATA transfer from card to host
        if (pCommand->isRead) {
            do {
                SDSPI_Read(pSdSpi, &dataHeader, 1);
                dataRetry1 --;
                if (dataHeader == SDSPI_START_BLOCK_1) {
                    break;
                }
                else if((dataHeader & 0xf0) == 0x00) {
                    pCommand->status = SDSPI_STATUS_ERROR;
                    TRACE_DEBUG("Data Error 0x%X!\n\r", dataHeader);
                    return 1;
                }
            } while(dataRetry1 > 0);

            if (dataRetry1 == 0) {
                TRACE_DEBUG("Timeout dataretry1\n\r");
                return 1;
            }

            SDSPI_Read(pSdSpi, pData, blockSize);

            // Specific for Cmd9()
            if ((pCommand->cmd & 0x3f) != 0x9) {

                SDSPI_Read(pSdSpi, crc, 2);
#ifdef SDSPI_CRC_ON
                // Check data CRC
                TRACE_DEBUG("Check Data CRC\n\r");
                crcPrev = 0;
                crcPrev2 = 0;
                if (crc[0] != ((crc_itu_t(crcPrev, pData, blockSize) & 0xff00) >> 8 )
                 || crc[1] !=  (crc_itu_t(crcPrev2, pData, blockSize) & 0xff)) {
                    TRACE_ERROR("CRC error 0x%X 0x%X 0x%X\n\r", \
                        crc[0], crc[1], crc_itu_t(pData, blockSize));
                    return 1;
                }
#endif
            }
        }

        // DATA transfer from host to card
        else {
            SDSPI_NCS(pSdSpi);
            if ((pCommand->conTrans == SPI_CONTINUE_TRANSFER) || ((pCommand->cmd & 0x3f) == 25)) {
                dataHeader = SDSPI_START_BLOCK_2;
            }
            else {
                dataHeader = SDSPI_START_BLOCK_1;
            }

            crcPrev = 0;
            crc[0] = (crc_itu_t(crcPrev, pData, blockSize) & 0xff00) >> 8;
            crcPrev2 = 0;
            crc[1] = (crc_itu_t(crcPrev2, pData, blockSize) & 0xff);
            SDSPI_Write(pSdSpi, &dataHeader, 1);
            SDSPI_Write(pSdSpi, pData, blockSize);
            SDSPI_Write(pSdSpi, crc, 2);

            // If status bits in data response is not "data accepted", return error
            if ((SDSPI_GetDataResp(pSdSpi, pCommand) & 0xe) != 0x4) {
                TRACE_ERROR("Write resp error!\n\r");
                return 1;
            }

            do {
                if (SDSPI_WaitDataBusy(pSdSpi) == 0) {
                    break;
                }
                dataRetry2--;
            } while(dataRetry2 > 0);
        }
        pData += blockSize;
        pCommand->nbBlock--;
    }

    if (pCommand->status == SDSPI_STATUS_PENDING) {
        pCommand->status = 0;
    }

    //TRACE_DEBUG("end SDSPI_SendCommand\n\r");
    return 0;
}