📄 sdhcslot.cpp
字号:
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;
// wIntSignalEn = ReadWord(SDHC_NORMAL_INT_SIGNAL_ENABLE); // KYS
// wIntSignalEn |= NORMAL_INT_ENABLE_CMD_COMPLETE | NORMAL_INT_ENABLE_TRX_COMPLETE; // KYS
// 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;
#ifdef _MMC_SPEC_42_
// Date : 07.05.14
// Developer : HS.JANG
// Description : to support MMCMicro this code was added
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 (UseDmaForRequest(pRequest)) {
// 08.05.30 by KYS
// Note that we can not know the next address if use DMA interrupt, so DMA should be disabled!.
//wIntStatusEn |= NORMAL_INT_ENABLE_DMA;
// wIntSignalEn |= NORMAL_INT_SIGNAL_DMA; // KYS
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 4k
DEBUGMSG(SDHC_SEND_ZONE,(TEXT("Sending command block size 0x%04X\r\n"), (WORD) pRequest->BlockSize));
//WriteWord(SDHC_BLOCKSIZE, (WORD) pRequest->BlockSize);
//WriteWord(SDHC_BLOCKSIZE, (WORD)( (0x7<<12) | pRequest->BlockSize )); // KYS
// 08.05.30 by KYS
// BlockSize
// Note that for DMA we are programming the buffer boundary for 512k beacause we cat not know the next address if use DMA interrupt.
WriteWord(SDHC_BLOCKSIZE, (WORD)(pRequest->BlockSize & 0xfff) | (0x7<<12));
// 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>(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;
}
// The following is required for the Pegasus. If it is not present,
// command-only transfers will sometimes fail (especially R1B and R5B).
WriteDword(SDHC_SYSTEMADDRESS_LO, 0);
WriteWord(SDHC_BLOCKSIZE, 0);
WriteWord(SDHC_BLOCKCOUNT, 0);
}
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);
// WriteWord(SDHC_NORMAL_INT_SIGNAL_ENABLE, wIntSignalEn); // KYS
// 08.03.27, by KYS
// Status Busy bit checking for clearing the interrupt status register before "CMD ISSUE".
while(ReadDword(SDHC_CONTROL4)&(0x1));
// 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);
// 08.04.21 by KYS
// Polling the command complete for "Real" FastPath
PollingForCommandComplete();
status = SD_API_STATUS_PENDING;
EXIT:
return status;
}
// 08.04.21 by KYS
// This polling function is needed for Fastpath and perform polling the command complete.
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();
// 08.01.27 by KYS
// you can also activate below code "continue;" in order to ensure the fastpath.
// then, you don't need to keep the fastpath status varible at "HandleCommandComplete" function.
//continue;
fContinue = FALSE; // Comment out this orginal line by KYS
}
// 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;
}
}
#ifndef _SMDK6410_CH0_EXTCD_
VOID
CSDHCSlotBase::HandleInterrupt(
)
#else
// 08.03.20 by KYS
// New Interrupt handler function can process factors on new card detect interrupt of HSMMC ch0 on SMDK6410.
VOID CSDHCSlotBase::HandleInterrupt(SDSLOT_INT_TYPE intType)
#endif
{
Validate();
#ifdef _SMDK6410_CH0_EXTCD_
// in case of it is occurred a card detect interrupt of HSMMC ch0 on SMDK6410
if (intType == SDSLOT_INT_CARD_DETECTED) {
RETAILMSG(0,(TEXT("[HSMMC0] Card Insertion or Removal Detect!!\n")));
m_fCheckSlot = TRUE;
} else {
#endif
WORD wIntStatus = ReadWord(SDHC_NORMAL_INT_STATUS);
// if(g_initialInsertion != 1) {
// while(( wIntStatus=ReadWord(SDHC_NORMAL_INT_STATUS)) == 0);
// }
if (m_fFakeCardRemoval && m_fCardPresent) {
m_fFakeCardRemoval = FALSE;
HandleRemoval(TRUE);
}
if (wIntStatus != 0) {
DEBUGMSG(SDHC_INTERRUPT_ZONE,
(TEXT("HandleInterrupt (%u) - Normal Interrupt_Status=0x%02x\n"),
m_dwSlot, wIntStatus));
RETAILMSG(0,
(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);
HandleDma();
// do not break here. Continue to check TransferComplete.
}
// Buffer Read Ready handling
if (wIntStatus & NORMAL_INT_STATUS_BUF_READ_RDY ) {
// Clear status
WriteWord(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_BUF_READ_RDY);
HandleReadReady();
// do not break here. Continue to check TransferComplete.
}
// Buffer Write Ready handling
if (wIntStatus & NORMAL_INT_STATUS_BUF_WRITE_RDY ) {
// Clear status
WriteWord(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_BUF_WRITE_RDY);
HandleWriteReady();
// do not break here. Continue to check TransferComplete.
}
}
else {
// We received data transfer interrupt before command
// complete interrupt. Wait for the command complete before
// processing the data interrupt.
}
// Transfer Complete handling
if ( wIntStatus & NORMAL_INT_STATUS_TRX_COMPLETE ) {
// Clear status
WriteWord(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_TRX_COMPLETE | NORMAL_INT_STATUS_DMA);
HandleTransferDone();
}
// SDIO Interrupt Handling
if ( wIntStatus & NORMAL_INT_STATUS_CARD_INT ) {
DEBUGCHK(m_fSDIOInterruptsEnabled);
DEBUGMSG(SDHC_INTERRUPT_ZONE, (_T("SDHCControllerIst: Card interrupt!\n")));
// Because SDIO Interrupt is level triggered, we are not able to clear
// the status. The status should be cleared by the card
// we just disable the interrupt from Interrupt Signal Register
// and Interrupt Status Enable register, and indicate that
// the card is interrupting
EnableSDIOInterrupts(FALSE);
IndicateSlotStateChange(DeviceInterrupting);
}
// Card Detect Interrupt Handling
if (wIntStatus & (NORMAL_INT_STATUS_CARD_INSERTION | NORMAL_INT_STATUS_CARD_REMOVAL)) {
WriteWord(
SDHC_NORMAL_INT_STATUS,
NORMAL_INT_STATUS_CARD_INSERTION | NORMAL_INT_STATUS_CARD_REMOVAL);
m_fCheckSlot = TRUE;
}
}
#ifdef _SMDK6410_CH0_EXTCD_
} // The end of "if(intType == SDSLOT_INT_CARD_DETECTED)"
#endif
if (m_fCheckSlot) {
m_fCheckSlot = FALSE;
#ifdef _SMDK6410_CH0_EXTCD_
// At this time, we have to validate the card present status.
if((IsCardPresent() == TRUE) && (m_fCardPresent != TRUE))
#else
// check card inserted or removed
DWORD dwPresentState = ReadDword(SDHC_PRESENT_STATE);
if (dwPresentState & STATE_CARD_INSERTED)
#endif
{
DEBUGMSG(SDHC_INTERRUPT_ZONE, (TEXT("SDHCControllerIst - Card is Inserted! \n")));
RETAILMSG(1, (TEXT("[HSMMC0] Card is Inserted! \n")));
m_fFakeCardRemoval = FALSE; // KYS
if (m_fCardPresent != TRUE ) {
Start();
HandleInsertion();
}
}
#ifdef _SMDK6410_CH0_EXTCD_
else if((IsCardPresent() != TRUE) && (m_fCardPresent != FALSE))
#else
else
#endif
{
DEBUGMSG(SDHC_INTERRUPT_ZONE, (TEXT("SDHCControllerIst - Card is Removed! \n")));
RETAILMSG(1, (TEXT("[HSMMC0] Card is Removed! \n")));
m_fFakeCardRemoval = FALSE; // KYS
if (m_fCardPresent) {
HandleRemoval(TRUE);
}
}
}
}
#ifdef _SMDK6410_CH0_EXTCD_
// New function can detect whether card is presented of HSMMC ch0 on SMDK6410.
BOOL CSDHCSlotBase::IsCardPresent()
{
BOOL fRetVal;
volatile S3C6410_GPIO_REG *pIOPreg = NULL;
pIOPreg = (volatile S3C6410_GPIO_REG *)DrvLib_MapIoSpace(S3C6410_BASE_REG_PA_GPIO, sizeof(S3C6410_GPIO_REG), FALSE);
if (pIOPreg == NULL) {
RETAILMSG (1,(TEXT("[HSMMC0] GPIO registers not mapped\r\n")));
return FALSE;
}
if ( (pIOPreg->GPNDAT & (0x1<<13)) == 0 ) {
fRetVal = TRUE;
} else {
fRetVal = FALSE;
}
RETAILMSG(0,(TEXT("IsCardPresent() : fRetVal = %d GPNDAT = 0x%x\r\n"), fRetVal, (pIOPreg->GPNDAT & (0x1<<13)) ));
DrvLib_UnmapIoSpace((PVOID)pIOPreg);
return fRetVal;
}
#endif
VOID
CSDHCSlotBase::HandleRemoval(
BOOL fCancelRequest
)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -