📄 sdhcslot.cpp
字号:
SDHC_CAPABILITIES_MAX_BLOCK_LENGTH_2
};
SSDHC_CAPABILITIES caps = GetCapabilities();
// Determine the maximum block length
DEBUGCHK(caps.bits.MaxBlockLen < dim(sc_rgusBlockLen));
DWORD dwMaxBlockLen = sc_rgusBlockLen[caps.bits.MaxBlockLen];
DEBUGCHK(dwMaxBlockLen <= SDHC_MAX_BLOCK_LENGTH);
return dwMaxBlockLen;
}
DWORD
CSDHCSlotBase::DetermineTimeoutControl(
)
{
// We try to come as close to the desired timeout without going below it.
DEBUGCHK(m_pregDevice->IsOK());
SSDHC_CAPABILITIES caps = GetCapabilities();
// Determine the DAT line timeout divisor.
// We allow the registry to override what is in the capabilities register.
DWORD dwTimeoutClock = m_pregDevice->ValueDW(SDHC_TIMEOUT_FREQUENCY_KEY);
if (dwTimeoutClock == 0) {
dwTimeoutClock = caps.bits.TOFreq * 1000;
if (dwTimeoutClock == 0) {
dwTimeoutClock = SDHC_MAX_CLOCK_FREQUENCY;
DEBUGMSG(SDCARD_ZONE_ERROR,
(_T("SDHC: No timeout frequency specified. Using default of %u\n"),
dwTimeoutClock));
}
else if (caps.bits.TimeoutUnit == 1) {
// listing is in MHz, not KHz
dwTimeoutClock *= 1000;
}
}
DEBUGCHK(dwTimeoutClock != 0);
DWORD dwTimeoutInMS = m_pregDevice->ValueDW(SDHC_TIMEOUT_KEY,
SDHC_DEFAULT_TIMEOUT);
DOUBLE dTimeoutControl = SdhcTimeoutSecondsToControl(dwTimeoutClock,
dwTimeoutInMS / 1000.0);
DWORD dwTimeoutControl;
if (dTimeoutControl < 0) {
dwTimeoutControl = 0;
}
else {
dTimeoutControl = ceil(dTimeoutControl);
dwTimeoutControl= (DWORD) dTimeoutControl;
}
dwTimeoutControl = min(dwTimeoutControl, SDHC_TIMEOUT_CONTROL_MAX);
#ifdef DEBUG
{
TCHAR szTimeout[4];
DOUBLE dActualTimeout = SdhcTimeoutControlToSeconds(dwTimeoutClock,
dwTimeoutControl);
_sntprintf(szTimeout, dim(szTimeout), _T("%0.1f"), dActualTimeout);
DEBUGCHK(szTimeout[dim(szTimeout) - 1] == 0);
szTimeout[dim(szTimeout) - 1] = 0; // Null-terminate
DEBUGMSG(SDCARD_ZONE_INIT, (_T("SDHC: Using timeout control value of 0x%x for %s seconds\n"),
dwTimeoutControl, szTimeout));
}
#endif
dwTimeoutControl = 0xe;
return dwTimeoutControl;
}
DWORD
CSDHCSlotBase::DetermineWakeupSources(
)
{
DEBUGCHK(m_pregDevice->IsOK());
DWORD dwWakeupSources = m_pregDevice->ValueDW(SDHC_WAKEUP_SOURCES_KEY);
dwWakeupSources &= WAKEUP_ALL_SOURCES;
// Waking on SDIO interrupts must be enabled by the bus driver.
dwWakeupSources &= ~WAKEUP_INTERRUPT;
return dwWakeupSources;
}
VOID
CSDHCSlotBase::SetVoltage(
DWORD dwVddSetting
)
{
Validate();
RETAILMSG(0,(TEXT("CSDHCSlotBase::SetVoltage 0x%X\n"),dwVddSetting));
UCHAR ucVoltageSelection = SDBUS_POWER_ON;
UCHAR ucOldVoltage;
DEBUGCHK(dwVddSetting & m_dwVddWindows);
if ( dwVddSetting &
(SD_VDD_WINDOW_3_2_TO_3_3 | SD_VDD_WINDOW_3_3_TO_3_4) ) {
ucVoltageSelection |= SDBUS_VOLTAGE_SELECT_3_3V;
}
else if ( dwVddSetting &
(SD_VDD_WINDOW_2_9_TO_3_0 | SD_VDD_WINDOW_3_0_TO_3_1) ) {
ucVoltageSelection |= SDBUS_VOLTAGE_SELECT_3_0V;
}
else if ( dwVddSetting &
(SD_VDD_WINDOW_1_7_TO_1_8 | SD_VDD_WINDOW_1_8_TO_1_9) ) {
ucVoltageSelection |= SDBUS_VOLTAGE_SELECT_1_8V;
}
ucOldVoltage = ReadByte(SDHC_POWER_CONTROL);
if (ucOldVoltage != ucVoltageSelection) {
// SD Bus Power must be initially set to 0 when changing voltages
WriteByte(SDHC_POWER_CONTROL, 0);
WriteByte(SDHC_POWER_CONTROL, ucVoltageSelection);
WriteByte(SDHC_POWER_CONTROL, ucVoltageSelection);
RETAILMSG(0,(
TEXT("CSDHCSlotBase::SetVoltage: Set SDHC_POWER_CONTROL reg = 0x%02x %d\n"),
ReadByte(SDHC_POWER_CONTROL),GetPowerSupplyRampUpMs()));
DEBUGMSG(SDCARD_ZONE_INFO,(
TEXT("CSDHCSlotBase::SetVoltage: Set SDHC_POWER_CONTROL reg = 0x%02x\n"),
ucVoltageSelection));
Sleep(GetPowerSupplyRampUpMs());
}
}
// Set up the controller according to the interface parameters.
VOID
CSDHCSlotBase::SetInterface(
PSD_CARD_INTERFACE pInterface
)
{
PREFAST_DEBUGCHK(pInterface);
Validate();
RETAILMSG(0,(TEXT("CSDHCSlotBase::SetInterface %d\n"),pInterface->InterfaceMode));
if (SD_INTERFACE_SD_MMC_1BIT == pInterface->InterfaceMode) {
DEBUGMSG(SDCARD_ZONE_INIT,
(TEXT("SHCSDSlotOptionHandler - Setting for 1 bit mode \n")));
RETAILMSG(1,
(TEXT("SHCSDSlotOptionHandler - Setting for 1 bit mode , Clock Rate =%d \n"),pInterface->ClockRate));
WriteByte(SDHC_HOST_CONTROL, 0);
m_f4BitMode = FALSE;
} else if (SD_INTERFACE_SD_4BIT == pInterface->InterfaceMode) {
DEBUGMSG(SDCARD_ZONE_INIT,
(TEXT("SHCSDSlotOptionHandler - Setting for 4 bit mode \n")));
RETAILMSG(1,
(TEXT("SHCSDSlotOptionHandler - Setting for 4 bit mode , Clock Rate =%d \n"),pInterface->ClockRate));
WriteByte(SDHC_HOST_CONTROL, HOSTCTL_DAT_WIDTH);
m_f4BitMode = TRUE;
} else if (SD_INTERFACE_MMC_8BIT == pInterface->InterfaceMode) {
DEBUGMSG(SDCARD_ZONE_INIT,
(TEXT("SHCSDSlotOptionHandler - Setting for 8 bit mode \n")));
RETAILMSG(1,
(TEXT("SHCSDSlotOptionHandler - Setting for 8 bit mode , Clock Rate =%d \n"),pInterface->ClockRate));
WriteByte(SDHC_HOST_CONTROL, HOSTCTL_DAT_WIDTH_8BIT|HOSTCTL_HIGHSPEED);
m_f4BitMode = TRUE;
}else {
DEBUGCHK(FALSE);
}
SetClockRate(&pInterface->ClockRate);
}
VOID
CSDHCSlotBase::SetPowerState(
CEDEVICE_POWER_STATE cpsNew
)
{
DEBUGCHK(VALID_DX(cpsNew));
m_fIsPowerManaged = TRUE;
if (DX_D1_OR_D2(cpsNew)) {
cpsNew = D0;
}
if (m_cpsCurrent != cpsNew) {
SetHardwarePowerState(cpsNew);
}
}
VOID
CSDHCSlotBase::PowerDown(
)
{
Validate();
m_cpsAtPowerDown = m_cpsCurrent;
if (!m_fIsPowerManaged) {
CEDEVICE_POWER_STATE cps;
if (m_bWakeupControl) {
cps = D3;
}
else {
cps = (_CEDEVICE_POWER_STATE)D4;
}
SetHardwarePowerState(cps);
}
BOOL fKeepPower = FALSE;
if (m_fSleepsWithPower || m_cpsCurrent == D0) {
DEBUGCHK(!m_fSleepsWithPower || m_cpsCurrent == D3);
fKeepPower = TRUE;
}
PowerUpDown(FALSE, fKeepPower);
}
VOID
CSDHCSlotBase::PowerUp(
)
{
Validate();
if (!m_fIsPowerManaged) {
SetHardwarePowerState(m_cpsAtPowerDown);
}
else if (m_fSleepsWithPower) {
WORD wIntStatus = ReadWord(SDHC_NORMAL_INT_STATUS);
if (wIntStatus == NORMAL_INT_STATUS_CARD_INT) {
// We woke system through a card interrupt. We need to clear
// this so that the IST will not be signalled.
EnableSDIOInterrupts(FALSE);
m_fPowerUpDisabledInts = TRUE;
}
}
PowerUpDown(TRUE, TRUE);
Start(); // added by JJG 06.11.11
}
SD_API_STATUS
CSDHCSlotBase::BusRequestHandler(
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);
RETAILMSG(0, (TEXT("%s CMD:%d\n"), pszFname, pRequest->CommandCode));
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) {
RETAILMSG(0,
(TEXT("%s AutoCMD12 Succeeded, bypass CMD12.\n"), pszFname));
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:
wRegCommand |= CMD_RESPONSE_R1_R5_R6;
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>(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;
wRegCommand |= CMD_DATA_PRESENT;
if (UseDmaForRequest(pRequest)) {
wIntStatusEn |= NORMAL_INT_ENABLE_DMA;
BOOL fNoException;
DEBUGCHK(TRANSFER_SIZE(pRequest) <= CB_DMA_BUFFER);
if (TRANSFER_IS_WRITE(pRequest)) {
DWORD cbToTransfer = TRANSFER_SIZE(pRequest);
SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {
fNoException = SDPerformSafeCopy(m_pbDmaBuffer,
pRequest->pBlockBuffer, cbToTransfer);
} SD_RESTORE_PROC_PERMISSIONS();
if (fNoException == FALSE) {
status = SD_API_STATUS_ACCESS_VIOLATION;
goto EXIT;
}
}
WriteDword(SDHC_SYSTEMADDRESS_LO, m_paDmaBuffer);
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 512K Bytes
DEBUGMSG(SDHC_SEND_ZONE,(TEXT("Sending command block size 0x%04X\r\n"), (WORD) pRequest->BlockSize));
WriteWord(SDHC_BLOCKSIZE, (WORD)((0x7<<12)| pRequest->BlockSize));
// 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);
/*
if(pRequest->CommandCode == 18 || pRequest->CommandCode == 25)
wRegTxnMode |= (TXN_MODE_MULTI_BLOCK | TXN_MODE_BLOCK_COUNT_ENABLE);
else
wRegTxnMode |= ( TXN_MODE_BLOCK_COUNT_ENABLE);*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -