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

📄 sdhc.cpp

📁 Windows CE 6.0 BSP for the Beagle Board.
💻 CPP
📖 第 1 页 / 共 5 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
// Portions Copyright (c) Texas Instruments.  All rights reserved. 
//

// Copyright (c) 2002 BSQUARE Corporation.  All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE

// SDHC controller driver implementation
#pragma optimize("",off)    // DEBUG
#include <SDCardDDK.h>
#include "SDHC.h"
#include <nkintr.h>
#include <pm.h>
#include <twl.h>

//------------------------------------------------------------------------------
//  Local Structures

//Debug the Power IOCTL's
//#define PM_TRACE 0
#define SDCARD_ZONE_POWER          DEBUGZONE(0)

#define DEFAULT_TIMEOUT_VALUE               60000
#define START_BIT                           0x00
#define TRANSMISSION_BIT                    0x00
#define START_RESERVED                      0x3F
#define END_RESERVED                        0xFE
#define END_BIT                             0x01

#define WAIT_FOR_INTERRUPT_TIMEOUT      500             // Time in milliseconds

#define IndicateSlotStateChange(event) \
    SDHCDIndicateSlotStateChange(m_pHCContext, \
    (UCHAR) 0, (event))

#define GetAndLockCurrentRequest() \
    SDHCDGetAndLockCurrentRequest(m_pHCContext, (UCHAR) 0)

#define TRANSFER_IS_WRITE(pRequest)        (SD_WRITE == (pRequest)->TransferClass)
#define TRANSFER_IS_READ(pRequest)         (SD_READ == (pRequest)->TransferClass)
#define TRANSFER_IS_COMMAND_ONLY(pRequest) (SD_COMMAND == (pRequest)->TransferClass)      

#define TRANSFER_SIZE(pRequest)            ((pRequest)->BlockSize * (pRequest)->NumBlocks)

static const GUID DEVICE_IFC_GPIO_GUID;
static const GUID DEVICE_IFC_TWL_GUID;

#ifdef DEBUG
// dump the current request info to the debugger
static 
VOID 
DumpRequest(
            PSD_BUS_REQUEST pRequest
            )
{   
    DEBUGCHK(pRequest);

    DEBUGMSG(SDCARD_ZONE_INIT, (L"DumpCurrentRequest: 0x%08X\r\n", pRequest)); 
    DEBUGMSG(SDCARD_ZONE_INIT, (L"\t Command: %d\r\n",  pRequest->CommandCode));
    DEBUGMSG(SDCARD_ZONE_INIT, (L"\t ResponseType: %d\r\n",  pRequest->CommandResponse.ResponseType)); 
    DEBUGMSG(SDCARD_ZONE_INIT, (L"\t NumBlocks: %d\r\n",  pRequest->NumBlocks)); 
    DEBUGMSG(SDCARD_ZONE_INIT, (L"\t BlockSize: %d\r\n",  pRequest->BlockSize)); 
    DEBUGMSG(SDCARD_ZONE_INIT, (L"\t HCParam: %d\r\n",    pRequest->HCParam)); 

}
#else
#define DumpRequest(ptr)
#endif



#if defined(DEBUG) || defined(ENABLE_RETAIL_OUTPUT)
#define HEXBUFSIZE 1024
char szHexBuf[HEXBUFSIZE];
#endif

struct CMD
{
    BYTE Cmd;           // 1 - this is a known SD CMD; 2 - this is a known SDIO CMD
    BYTE ACmd;          // 1 - this is a known ACMD
    BYTE MMCCmd;        // 1 - this is a known MMC CMD
    WORD CMD_TYPE;
    WORD ACMD_TYPE;
    WORD MMC_CMD_TYPE;
};

// table of command codes...  at this time only SD/SDIO commands are implemented
const CMD gwaCMD[] =
{
    { 1, 0, 0, 0x0000, 0x2000, 0x0000 }, // CMD 00
    { 0, 0, 1, 0x1000, 0x2000, 0x1040 }, // CMD 01 (known MMC command)
    { 1, 0, 1, 0x1000, 0x2000, 0x1040 }, // CMD 02
    { 1, 0, 1, 0x1000, 0x2000, 0x1040 }, // CMD 03
    { 1, 0, 0, 0x0000, 0x2000, 0x0000 }, // CMD 04
    { 2, 0, 0, 0x1000, 0x2000, 0x1000 }, // CMD 05
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 06
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 07
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 08
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 09
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 10
    { 0, 0, 1, 0xf000, 0x2000, 0xf040 }, // CMD 11 (known MMC command)
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 12
    { 1, 1, 0, 0x2000, 0x3000, 0x2000 }, // CMD 13
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 14
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 15
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 16
    { 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 17
    { 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 18
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 19
    { 0, 1, 1, 0x7000, 0x2000, 0x7000 }, // CMD 20 (known MMC command)
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 21
    { 0, 1, 0, 0x2000, 0x3000, 0x2000 }, // CMD 22
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 23 (known MMC command)
    { 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 24
    { 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 25
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 26
    { 1, 0, 0, 0x3000, 0x2000, 0x3000 }, // CMD 27
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 28
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 29
    { 1, 0, 0, 0x3000, 0x2000, 0x3000 }, // CMD 30
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 31
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 32
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 33
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 34
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 35
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 36
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 37
    { 1, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 38
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 39 (known MMC command)
    { 1, 1, 1, 0x2000, 0x2000, 0x2040 }, // CMD 40
    { 0, 1, 0, 0x1000, 0x1000, 0x1000 }, // CMD 41 (known MMC command)
    { 1, 1, 0, 0x3000, 0x2000, 0x3000 }, // CMD 42
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 43
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 44
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 45
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 46
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 47
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 48
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 49
    { 0, 1, 0, 0x2000, 0x2000, 0x2000 }, // CMD 50
    { 0, 1, 0, 0xb000, 0x3000, 0xb000 }, // CMD 51 (known MMC command)
    { 2, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 52
    { 2, 0, 0, 0x3000, 0x2000, 0x3000 }, // CMD 53
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 54
    { 1, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 55
    { 1, 0, 0, 0x3000, 0x2000, 0x3000 }, // CMD 56
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 57
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 58
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 59
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 60
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 61
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 62
    { 0, 0, 0, 0x2000, 0x2000, 0x2000 }, // CMD 63
};

CSDIOControllerBase::CSDIOControllerBase()
{
    InitializeCriticalSection( &m_critSec );
    m_fSDIOInterruptInService = FALSE;
    m_fFirstTime = TRUE;
    m_hControllerISTEvent = NULL;
    m_htControllerIST = NULL;
    m_dwControllerSysIntr = SYSINTR_UNDEFINED;
    m_hCardDetectEvent = NULL;
    m_htCardDetectIST = NULL;
    m_dwCardDetectSysIntr = SYSINTR_UNDEFINED;
    m_dwCardDetectSysIRQSize = -1;
    m_fAppCmdMode = FALSE;

    m_vpSDIOReg = NULL;
    m_fCardPresent = FALSE;
    m_fSDIOInterruptsEnabled = FALSE;
    
    m_dwMaxTimeout = DEFAULT_TIMEOUT_VALUE;
    m_bReinsertTheCard = FALSE;
    m_dwWakeupSources = 0;
    m_dwCurrentWakeupSources = 0;
    m_fMMCMode = FALSE;

    m_PowerState = D0;
}

WORD CSDIOControllerBase::Read_MMC_SDIO()
{
    WORD wVal;
    EnterCriticalSection( &m_critSec );
    wVal = INREG16(&m_vpSDIOReg->MMC_SDIO);
    LeaveCriticalSection( &m_critSec );
    return wVal;
}

void CSDIOControllerBase::Write_MMC_SDIO( WORD wVal )
{
    EnterCriticalSection( &m_critSec );
    OUTREG16(&m_vpSDIOReg->MMC_SDIO, wVal);
    LeaveCriticalSection( &m_critSec );
}

WORD CSDIOControllerBase::Read_MMC_STAT()
{
    WORD wVal;
    EnterCriticalSection( &m_critSec );
    wVal = INREG16(&m_vpSDIOReg->MMC_STAT);
    LeaveCriticalSection( &m_critSec );
    return wVal;
}

void CSDIOControllerBase::Write_MMC_STAT( WORD wVal )
{
    EnterCriticalSection( &m_critSec );
    OUTREG16(&m_vpSDIOReg->MMC_STAT,wVal);
    LeaveCriticalSection( &m_critSec );
}

//  Reset the controller.
VOID CSDIOControllerBase::SoftwareReset( BYTE bResetBits )
{
    WORD                bValue;
    DWORD               dwCurrentTickCount;
    DWORD               dwTimeout;
    DWORD               dwCountStart;
    BOOL                fTimeoutOverflow = FALSE;

    DEBUGCHK(sizeof(OMAP2420_SDIO_REGS) % sizeof(WORD) == 0);

    // Reset the controller
    OUTREG16(&m_vpSDIOReg->MMC_SYSC,(0x0002 & bResetBits));

    // calculate timeout conditions
    dwCountStart = GetTickCount();
    dwTimeout = dwCountStart + m_dwMaxTimeout;
    if( dwTimeout < dwCountStart )
        fTimeoutOverflow = TRUE;

    // Verify that reset has completed.
    do {
        bValue = INREG16(&m_vpSDIOReg->MMC_SISS);

        // check for a timeout
        dwCurrentTickCount = GetTickCount();
        if( fTimeoutOverflow ? ( dwTimeout < dwCurrentTickCount && dwCurrentTickCount < dwCountStart )
            : ( dwTimeout < dwCurrentTickCount || dwCurrentTickCount < dwCountStart ) )
        {
            DEBUGMSG(SDCARD_ZONE_ERROR, (L"CSDIOControllerBase::SoftwareReset: "
                L"Exit: TIMEOUT.\r\n"
            ));
            break;
        }
    } while (bValue != 0);
}


// Set up the controller according to the interface parameters.
VOID 
CSDIOControllerBase::SetInterface(
                                  PSD_CARD_INTERFACE pInterface
                                  )
{            
    DEBUGCHK(pInterface);

    WORD wRegValue;

    if (SD_INTERFACE_SD_MMC_1BIT == pInterface->InterfaceMode) 
    {
        DEBUGMSG(SDCARD_ZONE_INIT, (L"CSDIOControllerBase::SetInterface: "
            L"Setting for 1 bit mode\r\n"
        ));
        wRegValue = INREG16(&m_vpSDIOReg->MMC_CON);
        OUTREG16(&m_vpSDIOReg->MMC_CON, (wRegValue & (~VALUE_MMC_CON_DW_4BIT)));

        DEBUGMSG(SDCARD_ZONE_INIT, (L"CSDIOControllerBase::SetInterface: "
            L"MMC1_CON value = %X\r\n", INREG16(&m_vpSDIOReg->MMC_CON)
        ));
    } 
    else if (SD_INTERFACE_SD_4BIT == pInterface->InterfaceMode) 
    {
        DEBUGMSG(SDCARD_ZONE_INIT, (L"CSDIOControllerBase::SetInterface: "
            L"Setting for 4 bit mode \r\n"
        ));
        wRegValue = INREG16(&m_vpSDIOReg->MMC_CON);
        OUTREG16(&m_vpSDIOReg->MMC_CON, (wRegValue | (VALUE_MMC_CON_DW_4BIT)));

        DEBUGMSG(SDCARD_ZONE_INIT, (L"CSDIOControllerBase::SetInterface: "
            L"MMC1_CON value = %X\r\n", INREG16(&m_vpSDIOReg->MMC_CON)
        ));
    } 
    else 
    {
        DEBUGCHK(FALSE);
    }

    ClockOff();
    SetClockRate(&pInterface->ClockRate);
    ClockOn();
}


// Enable SDIO Interrupts.
VOID 
CSDIOControllerBase::EnableSDIOInterrupts()
{
    ASSERT( !m_fSDIOInterruptsEnabled );
    DEBUGMSG(SHC_INTERRUPT_ZONE, (L"+CSDHCSlot::EnableSDIOInterrupts\r\n"));

    WORD wRegValue = Read_MMC_SDIO();
    wRegValue |= MMC_IE_EOC;
    Write_MMC_SDIO(wRegValue);
    SETREG16(&m_vpSDIOReg->MMC_IE, MMC_IE_CIRQ);

    m_fSDIOInterruptsEnabled = TRUE;
}


// Acknowledge an SDIO Interrupt.
VOID CSDIOControllerBase::AckSDIOInterrupt(
    )
{   
    ASSERT( m_fSDIOInterruptsEnabled );

    DEBUGMSG(SHC_INTERRUPT_ZONE, (L"+CSDHCSlot::AckSDIOInterrupt\r\n"));

    WORD wRegValue = Read_MMC_STAT();
    Write_MMC_STAT(MMC_STAT_CIRQ);
    wRegValue = Read_MMC_STAT();
    if( wRegValue & MMC_STAT_CIRQ )
    {
        SDHCDIndicateSlotStateChange(m_pHCContext, 0, DeviceInterrupting);
    }
    else
    {
        SETREG16(&m_vpSDIOReg->MMC_IE, MMC_IE_CIRQ);
        m_fSDIOInterruptInService = FALSE;
    }
}


// Disable SDIO Interrupts.
VOID 
CSDIOControllerBase::DisableSDIOInterrupts()
{            
    ASSERT( m_fSDIOInterruptsEnabled );
    DEBUGMSG(SHC_INTERRUPT_ZONE, (L"+CSDHCSlot::DisableSDIOInterrupts\r\n"));
    
    CLRREG16(&m_vpSDIOReg->MMC_IE, MMC_IE_CIRQ);
    WORD wRegValue = Read_MMC_SDIO();
    wRegValue &= (~MMC_IE_EOC);
    Write_MMC_SDIO(wRegValue);

    m_fSDIOInterruptsEnabled = FALSE;
}


//  Set clock rate based on HC capability
VOID 
CSDIOControllerBase::SetClockRate(PDWORD pdwRate)
{
    const DWORD dwClockRate = *pdwRate;

    // calculate the register value
    WORD wDiv = (WORD)((MMCSD_CLOCK_INPUT + dwClockRate - 1) / dwClockRate);
    DEBUGMSG(SHC_CLOCK_ZONE, (L"CSDIOControllerBase::SetClockRate: "
        L"Actual wDiv = 0x%x  requested:0x%x ", wDiv, *pdwRate
    ));
    // Only 8 bits available for the divider, so mmc base clock / 255 is minimum.
    if ( wDiv > 0x03FF )

⌨️ 快捷键说明

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