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

📄 sdhcslot.cpp

📁 6410BSP3
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    }
    if (!m_fCardPresent) {
        status= SD_API_STATUS_DEVICE_REMOVED;
    }
    else {
        WORD wIntSignals = ReadWord(SDHC_NORMAL_INT_SIGNAL_ENABLE);
        WriteWord(SDHC_NORMAL_INT_SIGNAL_ENABLE,0);
        m_fCurrentRequestFastPath = FALSE ;
        m_pCurrentRequest = pRequest ;
        // if no data transfer involved, use FAST PATH
        if ((pRequest->SystemFlags & SD_FAST_PATH_AVAILABLE)!=0) { // Fastpath
            m_fCurrentRequestFastPath = TRUE;
            status = SubmitBusRequestHandler( pRequest );
            if( status == SD_API_STATUS_PENDING ) { // Polling for completion.
                BOOL fCardInserted = TRUE;
                DWORD dwStartTicks = GetTickCount();
                while (m_pCurrentRequest &&
                        (fCardInserted = (ReadDword(SDHC_PRESENT_STATE) & STATE_CARD_INSERTED)!=0 ) &&
                        ((GetTickCount() - dwStartTicks) <= m_dwFastPathTimeoutTicks)) {
                    HandleInterrupt();
                }

                if (m_pCurrentRequest && fCardInserted ) {
                    // Time out , need to switch to asyn.it will call callback after this
                    pRequest->SystemFlags &= ~SD_FAST_PATH_AVAILABLE;
                    m_fCurrentRequestFastPath = FALSE ;
                }
                else { // Fastpass completed.
                    status = m_FastPathStatus;
                    // Clear before status of fastpath.
                    m_FastPathStatus = 0;
                    if (m_pCurrentRequest) {
                        ASSERT(FALSE);
                        status = SD_API_STATUS_DEVICE_REMOVED;
                    }
                }
            }
            if (status == SD_API_STATUS_SUCCESS) {
                status = SD_API_STATUS_FAST_PATH_SUCCESS;
            }
        }
        else
            status = SubmitBusRequestHandler( pRequest );

        if (status!=SD_API_STATUS_PENDING && m_pCurrentRequest) { 
            // if there is error case. We don't notify the callback function either So.
            m_fCurrentRequestFastPath = TRUE;
            IndicateBusRequestComplete(pRequest,status);
        }
        WriteWord(SDHC_NORMAL_INT_SIGNAL_ENABLE,wIntSignals);
    }

    return status;
}


    SD_API_STATUS
CSDHCSlotBase::SubmitBusRequestHandler(PSD_BUS_REQUEST pRequest)
{
    SETFNAME();

    PREFAST_DEBUGCHK(pRequest);
    Validate();

    WORD            wRegCommand;
    SD_API_STATUS   status;
    WORD            wIntStatusEn;
    BOOL            fSuccess;

    DEBUGCHK(m_dwReadyInts == 0);
    DEBUGCHK(!m_fCommandCompleteOccurred);

    DEBUGMSG(SDHC_SEND_ZONE, (TEXT("%s CMD:%d\n"), pszFname, pRequest->CommandCode));

    // bypass CMD12 if AutoCMD12 was done by hardware
    if (pRequest->CommandCode == 12) {
        if (m_fAutoCMD12Success) {
            DEBUGMSG(SDHC_SEND_ZONE, 
                    (TEXT("%s AutoCMD12 Succeeded, bypass CMD12.\n"), pszFname));
            // The response for Auto CMD12 is in a special area
            UNALIGNED DWORD *pdwResponseBuffer = 
                (PDWORD) (pRequest->CommandResponse.ResponseBuffer + 1); // Skip CRC
            *pdwResponseBuffer = ReadDword(SDHC_R6);
            IndicateBusRequestComplete(pRequest, SD_API_STATUS_SUCCESS);
            status = SD_API_STATUS_SUCCESS;
            goto EXIT;
        }
    }

    m_fAutoCMD12Success = FALSE;

    // initialize command register with command code
    wRegCommand = (pRequest->CommandCode << CMD_INDEX_SHIFT) & CMD_INDEX_MASK;

    // check for a response
    switch (pRequest->CommandResponse.ResponseType) {
        case NoResponse:
            break;

        case ResponseR2:
            wRegCommand |= CMD_RESPONSE_R2;
            break;

        case ResponseR3:
        case ResponseR4:
            wRegCommand |= CMD_RESPONSE_R3_R4;
            break;

        case ResponseR1:
        case ResponseR5:
        case ResponseR6:
        case ResponseR7:
            wRegCommand |= CMD_RESPONSE_R1_R5_R6_R7;
            break;

        case ResponseR1b:
            wRegCommand |= CMD_RESPONSE_R1B_R5B;   
            break;

        default:
            status = SD_API_STATUS_INVALID_PARAMETER;
            goto EXIT;
    }

    // Set up variable for the new interrupt sources. Note that we must
    // enable DMA and read/write interrupts in this routine (not in
    // HandleCommandComplete) or they will be missed.
    wIntStatusEn = ReadWord(SDHC_NORMAL_INT_STATUS_ENABLE);
    wIntStatusEn |= NORMAL_INT_ENABLE_CMD_COMPLETE | NORMAL_INT_ENABLE_TRX_COMPLETE;

    // check command inhibit, wait until OK
    fSuccess = WaitForReg<DWORD>(&CSDHCSlotBase::ReadDword, SDHC_PRESENT_STATE, STATE_CMD_INHIBIT, 0);
    if (!fSuccess) {
        DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Timeout waiting for CMD Inhibit\r\n"),
                    pszFname));
        status = SD_API_STATUS_DEVICE_NOT_RESPONDING;
        goto EXIT;
    }

    // programming registers
    if (!TRANSFER_IS_COMMAND_ONLY(pRequest)) {
        WORD wRegTxnMode = 0;        
#ifdef _MMC_SPEC_42_
        // To distinguish btween MMCmicro and MMCplus, we will issue MMC_CMD_SEND_EXT_CSD.
        // At that time, Dat line is 8bit. If the inserted card is MMCmicro, "Data timeout" error will be occurred.
        // Because MMCmicro does not supports 8bit DAT line but 4bit. To reduce the delay time on Data timeout error occurring,
        // we modify the timeout value.
        if ( (ReadByte(SDHC_TIMEOUT_CONTROL) != m_dwTimeoutControl) && 
                (pRequest->CommandCode != MMC_CMD_SEND_EXT_CSD) ) {
            WriteByte(SDHC_TIMEOUT_CONTROL, (BYTE) m_dwTimeoutControl);
        } else if ( (ReadByte(SDHC_TIMEOUT_CONTROL) == m_dwTimeoutControl) &&
                (pRequest->CommandCode == MMC_CMD_SEND_EXT_CSD) ) {
            WriteByte(SDHC_TIMEOUT_CONTROL, (BYTE)0x3);
        }
#endif
        wRegCommand |= CMD_DATA_PRESENT;

        if (m_SlotDma &&  m_SlotDma->ArmDMA(*pRequest,TRANSFER_IS_WRITE(pRequest))) {
            wIntStatusEn |= NORMAL_INT_ENABLE_DMA;
            wRegTxnMode |= TXN_MODE_DMA;
        }
        else {
            if (TRANSFER_IS_WRITE(pRequest)) {
                wIntStatusEn |= NORMAL_INT_ENABLE_BUF_WRITE_RDY;
            }
            else {
                wIntStatusEn |= NORMAL_INT_ENABLE_BUF_READ_RDY;
            }
        }

        // BlockSize
        // Note that for DMA we are programming the buffer boundary for 4k
        DEBUGMSG(SDHC_SEND_ZONE,(TEXT("Sending command block size 0x%04X\r\n"), (WORD) pRequest->BlockSize));
        ASSERT(PAGE_SIZE == 0x1000);
        WriteWord(SDHC_BLOCKSIZE, (WORD)(pRequest->BlockSize & 0xfff) | (0<<12)); // SDHC 2.2.2, CE is 4k-aligned page.

        // We always go into block mode even if there is only 1 block. 
        // Otherwise the Pegasus will occaissionally hang when
        // writing a single block with DMA.
        wRegTxnMode |= (TXN_MODE_MULTI_BLOCK | TXN_MODE_BLOCK_COUNT_ENABLE);

        // BlockCount
        DEBUGMSG(SDHC_SEND_ZONE,(TEXT("Sending command block count 0x%04X\r\n"), 
                    (WORD) pRequest->NumBlocks));            
        WriteWord(SDHC_BLOCKCOUNT, (WORD) pRequest->NumBlocks);

        if (pRequest->Flags & SD_AUTO_ISSUE_CMD12) {
            wRegTxnMode |= TXN_MODE_AUTO_CMD12;
        }

        if (TRANSFER_IS_READ(pRequest)) {
            wRegTxnMode |= TXN_MODE_DATA_DIRECTION_READ;     
        }

        // check dat inhibit, wait until okay
        fSuccess = WaitForReg<DWORD>(&CSDHCSlotBase::ReadDword, SDHC_PRESENT_STATE, STATE_DAT_INHIBIT, 0); 
        if (!fSuccess) {
            DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Timeout waiting for DAT Inhibit\r\n"),
                        pszFname));
            status = SD_API_STATUS_DEVICE_NOT_RESPONDING;
            goto EXIT;
        }

        DEBUGMSG(SDHC_SEND_ZONE,(TEXT("Sending Transfer Mode 0x%04X\r\n"),wRegTxnMode));
        WriteWord(SDHC_TRANSFERMODE, wRegTxnMode);
    }
    else {
        // Command-only
        if (pRequest->CommandCode == SD_CMD_STOP_TRANSMISSION) {
            wRegCommand |= CMD_TYPE_ABORT;
        }
        else if (TransferIsSDIOAbort(pRequest)) {
            // Use R5b For CMD52, Function 0, I/O Abort
            DEBUGMSG(SDHC_SEND_ZONE, (TEXT("Sending Abort command \r\n")));
            wRegCommand |= CMD_TYPE_ABORT | CMD_RESPONSE_R1B_R5B;
        }
    }

    DEBUGMSG(SDHC_SEND_ZONE,(TEXT("Sending command register 0x%04X\r\n"),wRegCommand));
    DEBUGMSG(SDHC_SEND_ZONE,(TEXT("Sending command Argument 0x%08X\r\n"),pRequest->CommandArgument));

    WriteDword(SDHC_ARGUMENT_0, pRequest->CommandArgument);

    // Enable transfer interrupt sources.
    WriteWord(SDHC_NORMAL_INT_STATUS_ENABLE, wIntStatusEn);

    // Status Busy bit checking for clearing the interrupt status register before "CMD ISSUE".
    fSuccess = WaitForReg<DWORD>(&CSDHCSlotBase::ReadDword, SDHC_CONTROL4, SDHC_CONTROL4_STABUSY, 0); 
    if (!fSuccess) {
        DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Timeout waiting for CMD operation finish\r\n"),
                    pszFname));
        status = SD_API_STATUS_DEVICE_NOT_RESPONDING;
        goto EXIT;
    }

    // Turn the clock on. It is turned off in IndicateBusRequestComplete().
    SDClockOn();

    // Turn the LED on.
    EnableLED(TRUE);

    // Writing the upper byte of the command register starts the command.
    // All register initialization must already be complete by this point.
    WriteWord(SDHC_COMMAND, wRegCommand);
    if (m_fCommandPolling  ) {
        PollingForCommandComplete();
    }
    status = SD_API_STATUS_PENDING;

EXIT:
    return status;
}

BOOL CSDHCSlotBase::PollingForCommandComplete()
{
    BOOL            fContinue = TRUE;
    if (m_fFakeCardRemoval && m_fCardPresent) {
        m_fFakeCardRemoval = FALSE;
        HandleRemoval(TRUE);
    }
    else {
        // Assume we reading PCI register at 66 Mhz. for times of 100 us. it should be 10*1000 time
        for (DWORD dwIndex=0; fContinue  && dwIndex<10*1000; dwIndex ++ ) {
            WORD wIntStatus = ReadWord(SDHC_NORMAL_INT_STATUS);
            if (wIntStatus != 0) {
                DEBUGMSG(SDHC_INTERRUPT_ZONE,
                        (TEXT("PollingForCommandComplete (%u) - Normal Interrupt_Status=0x%02x\n"),
                         m_dwSlot, wIntStatus));

                // Error handling. Make sure to handle errors first. 
                if ( wIntStatus & NORMAL_INT_STATUS_ERROR_INT ) {
                    HandleErrors();
                    fContinue = FALSE;
                }

                // Command Complete handling.
                if ( wIntStatus & NORMAL_INT_STATUS_CMD_COMPLETE ) {
                    // Clear status
                    m_fCommandCompleteOccurred = TRUE;
                    fContinue = FALSE;
                    WriteWord(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_CMD_COMPLETE);
                    if (HandleCommandComplete()) { // If completed. 
                        WriteWord(SDHC_NORMAL_INT_STATUS, (wIntStatus & NORMAL_INT_STATUS_TRX_COMPLETE));
                    }
                }
            }
        }
    }
    ASSERT(!fContinue);
    return (!fContinue);
}


VOID 
CSDHCSlotBase::EnableSDIOInterrupts(
        BOOL fEnable
        )
{
    Validate();

    if (fEnable) {
        m_fSDIOInterruptsEnabled = TRUE;
        DoEnableSDIOInterrupts(fEnable);
    }
    else {
        DoEnableSDIOInterrupts(fEnable);
        m_fSDIOInterruptsEnabled = FALSE;
    }
}


VOID 
CSDHCSlotBase::HandleInterrupt(
        )
{
    Validate();
    WORD wIntStatus = 0;
    wIntStatus = ReadWord(SDHC_NORMAL_INT_STATUS);

    if (m_fFakeCardRemoval ) {
        m_fFakeCardRemoval = FALSE;
        if (m_fCardPresent)
            HandleRemoval(TRUE);
        m_fCheckSlot = TRUE;
    }
    else if (wIntStatus != 0) {
        DEBUGMSG(SDHC_INTERRUPT_ZONE, 
                (TEXT("HandleInterrupt (%u) - Normal Interrupt_Status=0x%02x\n"),
                 m_dwSlot, wIntStatus));

        // Error handling. Make sure to handle errors first. 
        if ( wIntStatus & NORMAL_INT_STATUS_ERROR_INT ) {
            HandleErrors();
        }

        // Command Complete handling.
        if ( wIntStatus & NORMAL_INT_STATUS_CMD_COMPLETE ) {
            // Clear status
            m_fCommandCompleteOccurred = TRUE;
            WriteWord(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_CMD_COMPLETE);
            if ( HandleCommandComplete() ) {
                wIntStatus &= ~NORMAL_INT_STATUS_TRX_COMPLETE; // this is command-only request. 
            }
        }

        // Sometimes at the lowest clock rate, the Read/WriteBufferReady
        // interrupt actually occurs before the CommandComplete interrupt.
        // This confuses our debug validation code and could potentially
        // cause problems. This is why we will verify that the CommandComplete
        // occurred before processing any data transfer interrupts.
        if (m_fCommandCompleteOccurred) {
            if (wIntStatus & NORMAL_INT_STATUS_DMA) {
                WriteWord(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_DMA);
                // get the current request  
                PSD_BUS_REQUEST pRequest = GetAndLockCurrentRequest();
                if (m_SlotDma && pRequest) 
                    m_SlotDma->DMANotifyEvent(*pRequest, DMA_COMPLETE);
                else {

⌨️ 快捷键说明

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