📄 sdhcslot.cpp
字号:
// 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 {
RETAILMSG(0,(TEXT("Command Only\n")));
// 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);
}
if(pRequest->CommandCode == 1) pRequest->CommandArgument = 0xFF8000; // added by JJG
RETAILMSG(0,(TEXT("Sending command register 0x%04X\r\n"),wRegCommand));
RETAILMSG(0,(TEXT("Sending command Argument 0x%08X\r\n"),pRequest->CommandArgument));
RETAILMSG(0,(TEXT("Sending command IntStatusEn 0x%08X\r\n"),wIntStatusEn));
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);
// 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);
status = SD_API_STATUS_PENDING;
RETAILMSG(0,(TEXT("Sending command IntStatusEn 0x%08X\r\n"),ReadWord(SDHC_NORMAL_INT_STATUS_ENABLE)));
EXIT:
return status;
}
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 = ReadWord(SDHC_NORMAL_INT_STATUS);
RETAILMSG(0,(TEXT("Status = 0x%X\n"),wIntStatus));
if (m_fFakeCardRemoval && m_fCardPresent) {
RETAILMSG(0,(TEXT("Wakeup !!!!!! m_fFakeCardRemoval && m_fCardPresent\n")));
m_fFakeCardRemoval = FALSE;
HandleRemoval(TRUE);
}
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();
}
//if ( wIntStatus & NORMAL_INT_STATUS_CMD_COMPLETE ) {
// Command Complete handling.
else if ( wIntStatus & NORMAL_INT_STATUS_CMD_COMPLETE ) { // modifyed by JJG 06.10.11
// 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);
//WriteWord(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_CARD_INT);
//RETAILMSG(1,(TEXT("SDHC_NORMAL_INT_STATUS=0x%X\n"),ReadWord(SDHC_NORMAL_INT_STATUS)));
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;
}
}
if (m_fCheckSlot) {
m_fCheckSlot = FALSE;
// check card inserted or removed
DWORD dwPresentState = ReadDword(SDHC_PRESENT_STATE);
if (dwPresentState & STATE_CARD_INSERTED) {
RETAILMSG(1, (TEXT("+++++++++++++++++++++SDHCControllerIst - Card is Inserted! 0x%08X\n"),this));
DEBUGMSG(SDHC_INTERRUPT_ZONE, (TEXT("SDHCControllerIst - Card is Inserted! \n")));
m_fFakeCardRemoval = FALSE; // added by JJG 06.11.13
if (m_fCardPresent == FALSE ) {
HandleInsertion();
}
}
else {
RETAILMSG(1, (TEXT("------------------------SDHCControllerIst - Card is Removed! 0x%08X\n"),this));
DEBUGMSG(SDHC_INTERRUPT_ZONE, (TEXT("SDHCControllerIst - Card is Removed! \n")));
m_fFakeCardRemoval = FALSE; // added by JJG 06.11.13
if (m_fCardPresent) {
HandleRemoval(TRUE);
}
}
}
}
VOID
CSDHCSlotBase::HandleRemoval(
BOOL fCancelRequest
)
{
m_fCardPresent = FALSE;
m_fIsPowerManaged = FALSE;
m_fSleepsWithPower = FALSE;
m_fPowerUpDisabledInts = FALSE;
m_f4BitMode = FALSE;
m_cpsCurrent = D0;
// Wake on SDIO interrupt must be set by the client
m_bWakeupControl &= ~WAKEUP_INTERRUPT;
if (m_fSDIOInterruptsEnabled) {
EnableSDIOInterrupts(FALSE);
}
IndicateSlotStateChange(DeviceEjected);
// turn off clock and remove power from the slot
SDClockOff();
WriteByte(SDHC_POWER_CONTROL, 0);
if (fCancelRequest) {
// get the current request
PSD_BUS_REQUEST pRequest = GetAndLockCurrentRequest();
if (pRequest != NULL) {
DEBUGMSG(SDCARD_ZONE_WARN,
(TEXT("Card Removal Detected - Canceling current request: 0x%08X, command: %d\n"),
pRequest, pRequest->CommandCode));
DumpRequest(pRequest, SDHC_SEND_ZONE || SDHC_RECEIVE_ZONE);
IndicateBusRequestComplete(pRequest, SD_API_STATUS_DEVICE_REMOVED);
}
}
if (m_pbDmaBuffer) {
DEBUGCHK(m_paDmaBuffer);
FreePhysBuffer(m_pbDmaBuffer);
m_pbDmaBuffer = NULL;
m_paDmaBuffer = 0;
// The Pegasus requires the following so that the next
// insertion will work correctly.
SoftwareReset(SOFT_RESET_CMD | SOFT_RESET_DAT);
WriteDword(SDHC_SYSTEMADDRESS_LO, 0);
WriteWord(SDHC_BLOCKSIZE, 0);
WriteWord(SDHC_BLOCKCOUNT, 0);
WriteWord(SDHC_NORMAL_INT_STATUS, NORMAL_INT_STATUS_DMA);
}
}
VOID
CSDHCSlotBase::HandleInsertion(
)
{
DWORD dwClockRate = SD_DEFAULT_CARD_ID_CLOCK_RATE;
m_fCardPresent = TRUE;
// Apply the initial voltage to the card.
SetVoltage(GetMaxVddWindow());
// Send at least 74 clocks to the card over the course of at least 1 ms
// with allowance for power supply ramp-up time. (SD Phys Layer 6.4)
// Note that power supply ramp-up time occurs in SetVoltage().
RETAILMSG(0,(TEXT("++SetClockRate(&dwClockRate)\n")));
SetClockRate(&dwClockRate);
SDClockOn();
DWORD dwSleepMs = (74 / (dwClockRate / 1000)) + 1;
Sleep(dwSleepMs);
//while(1);
SDClockOff();
if (GetCapabilities().bits.DMA) {
RETAILMSG(0,(TEXT("Use DMA\n")));
PHYSICAL_ADDRESS SystemAddr = { 0 };
PVOID pvBuffer = AllocPhysBuffer(CB_DMA_BUFFER, &SystemAddr.LowPart);
if (pvBuffer) {
PHYSICAL_ADDRESS BusAddr;
// Translate physical address to logical (bus-relative) address.
BOOL fSuccess = TranslateSystemAddr(m_hBusAccess, m_interfaceType,
m_dwBusNumber, SystemAddr, &BusAddr);
if (fSuccess) {
RETAILMSG(0,(TEXT("Use DMA Success.\n")));
m_pbDmaBuffer= (PBYTE) pvBuffer;
m_paDmaBuffer = BusAddr.LowPart;
}
else {
// If we fail, we will simply fall back to PIO mode
FreePhysBuffer(pvBuffer);
}
}
}
// Interrupts are not enabled on a newly inserted card.
EnableSDIOInterrupts(FALSE);
// Indicate device arrival
IndicateSlotStateChange(DeviceInserted);
}
BOOL
CSDHCSlotBase::HandleCommandComplete(
)
{
SETFNAME();
PSD_BUS_REQUEST pRequest;
BOOL fRet = FALSE;
RETAILMSG(0,(TEXT("CSDHCSlotBase::HandleCommandComplete\n")));
// get the current request
pRequest = GetAndLockCurrentRequest();
DEBUGCHK(m_dwReadyInts == 0);
if (pRequest) {
RETAILMSG(0,(TEXT("CSDHCSlotBase::HandleCommandComplete pRequest\n")));
DEBUGCHK(pRequest->HCParam == 0);
SD_API_STATUS transferStatus = SD_API_STATUS_SUCCESS;
if (NoResponse != pRequest->CommandResponse.ResponseType) {
// Copy response over to request structure. Note that this is a
// bus driver buffer, so we do not need to SetProcPermissions
// or __try/__except.
UNALIGNED DWORD *pdwResponseBuffer =
(PDWORD) (pRequest->CommandResponse.ResponseBuffer + 1); // Skip CRC
WORD wCommand = ReadWord(SDHC_COMMAND);
if ((wCommand & CMD_RESPONSE_R1B_R5B) == CMD_RESPONSE_R1B_R5B) {
// wait for Transfer Complete status, which indicate the busy wait is over.
// we should not handle this TXN_COMPLETE interrupt in IST in this case
/*
RETAILMSG(0,(TEXT("HandleCommandComplete Status: 0x%X\n"),ReadWord(SDHC_NORMAL_INT_STATUS_ENABLE)));
RETAILMSG(0,(TEXT("HandleCommandComplete Signal: 0x%X\n"),ReadWord(SDHC_NORMAL_INT_SIGNAL_ENABLE)));
BOOL fSuccess = WaitForReg<WORD>(ReadWord, SDHC_NORMAL_INT_STATUS,
NORMAL_INT_STATUS_TRX_COMPLETE, NORMAL_INT_STATUS_TRX_COMPLETE, 5000);
RETAILMSG(0, (_T("%s Go waiting for NORMAL_INT_STATUS_TRX_COMPLETE\r\n"),
pszFname));
if (!fSuccess) {
RETAILMSG(0, (_T("%s Timeout waiting for NORMAL_INT_STATUS_TRX_COMPLETE\r\n"),
pszFname));
DEBUGMSG(SDCARD_ZONE_ERROR, (_T("%s Timeout waiting for NORMAL_INT_STATUS_TRX_COMPLETE\r\n"),
pszFname));
transferStatus = SD_API_STATUS_RESPONSE_TIMEOUT;
}*/
RETAILMSG(0,(TEXT("CSDHCSlotBase::HandleCommandComplete SoftwareReset\n")));
// Reset cmd and dat circuits
SoftwareReset(SOFT_RESET_CMD | SOFT_RESET_DAT);
}
pdwResponseBuffer[0] = ReadDword(SDHC_R0);
RETAILMSG(0,(TEXT("pdwResponseBuffer[0]= 0x%X\n"),pdwResponseBuffer[0]));
if (pRequest->CommandResponse.ResponseType == ResponseR2) {
pdwResponseBuffer[1] = ReadDword(SDHC_R2);
pdwResponseBuffer[2] = ReadDword(SDHC_R4);
pdwResponseBuffer[3] = ReadDword(SDHC_R6);
RETAILMSG(0,(TEXT("pdwResponseBuffer[1]= 0x%X\n"),pdwResponseBuffer[1]));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -