📄 sdiocontrollerbase.cpp
字号:
// CSDIOControllerBase::BusRequestHandler - bus request handler
// Input: Slot - slot the request is going on
// pRequest - the request
//
// Output:
// Return: SD_API_STATUS Code
// Notes: The request passed in is marked as uncancelable, this function
// has the option of making the outstanding request cancelable
//
///////////////////////////////////////////////////////////////////////////////
SD_API_STATUS CSDIOControllerBase::BusRequestHandler(DWORD dwSlot, PSD_BUS_REQUEST pRequest)
{
DEBUGMSG (SDCARD_ZONE_FUNC,(TEXT("BusRequestHandler starts (CMD:%d)\r\n"), pRequest->CommandCode));
SD_API_STATUS status;
// Reset FIFO and status registers
vm_pSDIReg->SDIFSTA |= FIFO_RESET;
vm_pSDIReg->SDIDSTA = 0xffff;
vm_pSDIReg->SDIDCON = 0;
vm_pSDIReg->SDICSTA = 0xffff;
vm_pSDIReg->SDICCON = 0;
Start_SDI_Clock();
//----- 1. Determine the type of command (data vs. no data) and send the command -----
m_dwNumBytesToTransfer = pRequest->BlockSize * pRequest->NumBlocks;
//----- 2 Can we schedule a DMA operation using the caller's buffer as-is? -----
if( ( m_dwDMAChannel == 0xffffffff ) || m_dwNumBytesToTransfer > MAXIMUM_DMA_TRANSFER_SIZE )
{
m_bUseDMAForTransfer = FALSE;
SetupPollingXfer(pRequest); // Use polling I/O routines for data transfer
}
else
{
if((IS_BUFFER_DWORD_ALIGNED(pRequest->pBlockBuffer)) && (IS_BUFFER_SIZE_A_DWORD_MULTPLE(pRequest->BlockSize)) )
{
m_DATATransferSize = 4; // DMA transfer size DWORD
if(pRequest->BlockSize == BYTES_PER_SECTOR)
m_bUseDMABurst = TRUE;
else
m_bUseDMABurst = FALSE;
}
else if ((IS_BUFFER_WORD_ALIGNED(pRequest->pBlockBuffer)) && (IS_BUFFER_SIZE_A_WORD_MULTPLE(pRequest->BlockSize)) )
{
m_DATATransferSize = 2; // DMA transfer size WORD
}
else
{
m_DATATransferSize = 1; // DMA transfer size BYTE
}
m_bUseDMAForTransfer = TRUE;
SetupDmaXfer(pRequest); // Use DMA for data transfer
}
if(pRequest->TransferClass == SD_COMMAND)
{
// Command only
status = SendCommand(pRequest->CommandCode, pRequest->CommandArgument, pRequest->CommandResponse.ResponseType, FALSE);
if(!SD_API_SUCCESS(status))
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHCDBusRequestHandler() - Error sending command:0x%02x\r\n"), pRequest->CommandCode));
goto BUS_REQUEST_COMPLETE;
}
//----- 2. Is this the first command sent to the card? If so, delay the 74 (or 80) clock cycles per the SD spec -----
if(m_bSendInitClocks)
{
m_bSendInitClocks = FALSE;
Wait_80_SDI_Clock_Cycles();
}
}
else
{
// Command with data transfer
status = SendCommand(pRequest->CommandCode, pRequest->CommandArgument, pRequest->CommandResponse.ResponseType, TRUE);
if(!SD_API_SUCCESS(status))
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHCDBusRequestHandler() - Error sending command:0x%02x\r\n"), pRequest->CommandCode));
goto BUS_REQUEST_COMPLETE;
}
}
//----- 3. Signal an IST that processes response information and cache our state -----
// NOTE: It is critical that this API NOT complete the bus request directly (which
// is why another thread is used). The bus driver expects bus requests to complete
// asynchronously and a stack overflow WILL eventually occur if this rule isn't honored.
SetEvent(m_hResponseReceivedEvent);
m_CurrentState = CommandSent;
status = SD_API_STATUS_PENDING;
BUS_REQUEST_COMPLETE:
DEBUGMSG (SDCARD_ZONE_FUNC,(TEXT("SDHCD:BusRequestHandler ends\r\n")));
return status;
}
//-------------------------------------- Interrupt Service Threads---------------------------------------
///////////////////////////////////////////////////////////////////////////////
// CSDIOControllerBase::TransferIstThread - IST thread for DMA channel dedicated to SDIO
// Input: pController - the controller instance
// Output:
// Return: Thread exit code
// Notes:
///////////////////////////////////////////////////////////////////////////////
DWORD CSDIOControllerBase::TransferIstThread()
{
PSD_BUS_REQUEST pRequest = NULL; // the request to complete
SD_API_STATUS status;
if( m_DMAIstThreadPriority != 0xffffffff && !CeSetThreadPriority( GetCurrentThread(), m_DMAIstThreadPriority ) )
{
DEBUGMSG(SDCARD_ZONE_WARN,(TEXT("SDHCDriver:TransferIstThread(): warning, failed to set CEThreadPriority \r\n")));
}
for(;;)
{
//----- 1. Wait for the command response -----
status = SD_API_STATUS_PENDING;
if(WaitForSingleObject(m_hResponseReceivedEvent, INFINITE) == WAIT_FAILED)
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCDriver:TransferIstThread(): Wait Failed!\r\n")));
return FALSE;
}
if(m_bDriverShutdown)
{
DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("SDHCD:TransferIstThread(): Thread Exiting\r\n")));
return FALSE;
}
//----- 2. Get and lock the current bus request -----
if(pRequest == NULL)
{
if((pRequest = SDHCDGetAndLockCurrentRequest(m_pHCContext, 0)) == NULL)
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - Unable to get/lock current request!\r\n")));
status = SD_API_STATUS_INVALID_DEVICE_REQUEST;
goto TRANSFER_DONE;
}
}
//----- 3. Get the response information -----
if(pRequest->CommandResponse.ResponseType == NoResponse)
{
goto TRANSFER_DONE;
}else{
status = GetCommandResponse(pRequest);
if(!SD_API_SUCCESS(status))
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHCDBusRequestHandler() - Error getting response for command:0x%02x\r\n"), pRequest->CommandCode));
goto TRANSFER_DONE;
}
}
//----- 4. SPECIAL CASE: The SD_CMD_STOP_TRANSMISSION that is sent after a SD_CMD_WRITE_MULTIPLE_BLOCK command -----
// requires a BUSY_CHECK
if( ( m_fHandleBusyCheckOnCommand38 && pRequest->CommandCode == SD_CMD_ERASE ) ||
( ( pRequest->CommandCode == SD_CMD_STOP_TRANSMISSION ) && ( m_dwLastTypeOfTransfer == SD_WRITE ) ) )
{
DWORD dwWaitCount = 0;
//----- 5. Wait until the I/O transfer is complete -----
while(!(vm_pSDIReg->SDIDSTA & BUSY_CHECKS_FINISH))
{
dwWaitCount++;
if( dwWaitCount > WAIT_TIME )
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - timeout waiting for BUSY_CHECKS to finish!\r\n")));
status = SD_API_STATUS_DATA_TIMEOUT;
goto TRANSFER_DONE;
}
if( !IsCardPresent() )
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - Card ejected!\r\n")));
status = SD_API_STATUS_DEVICE_REMOVED;
goto TRANSFER_DONE;
}
if((vm_pSDIReg->SDIFSTA & FIFO_FAIL_ERROR))
{
vm_pSDIReg->SDIDSTA = BUSY_CHECKS_FINISH;
vm_pSDIReg->SDIFSTA &= FIFO_FAIL_ERROR;
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - FIFO Error waiting for BUSY_CHECKS to finish!\r\n")));
status = SD_API_STATUS_DATA_ERROR;
goto TRANSFER_DONE;
}
if((vm_pSDIReg->SDIDSTA & DATA_TRANSMIT_CRC_ERROR))
{
vm_pSDIReg->SDIDSTA = BUSY_CHECKS_FINISH | DATA_TRANSMIT_CRC_ERROR;
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - Transmit CRC Error waiting for BUSY_CHECKS to finish!\r\n")));
status = SD_API_STATUS_DATA_ERROR;
goto TRANSFER_DONE;
}
if((vm_pSDIReg->SDIDSTA & DATA_RECEIVE_CRC_ERROR))
{
vm_pSDIReg->SDIDSTA = BUSY_CHECKS_FINISH | DATA_RECEIVE_CRC_ERROR;
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - Receive CRC Error waiting for BUSY_CHECKS to finish!\r\n")));
status = SD_API_STATUS_DATA_ERROR;
goto TRANSFER_DONE;
}
if((vm_pSDIReg->SDIDSTA & DATA_TIME_OUT))
{
vm_pSDIReg->SDIDSTA = BUSY_CHECKS_FINISH | DATA_TIME_OUT;
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - Data timeout waiting for BUSY_CHECKS to finish!\r\n")));
status = SD_API_STATUS_DATA_TIMEOUT;
goto TRANSFER_DONE;
}
}
vm_pSDIReg->SDIDSTA = BUSY_CHECKS_FINISH;
}
//----- 6. If this is a data transfer, start the I/O operation; otherwise, finish the request -----
if(pRequest->TransferClass == SD_COMMAND)
{
goto TRANSFER_DONE;
}
//----- 7. If this is a DMA transfer, we enable interrupts and wait for the DMA interrupt. Otherwise, -----
// we use our polling routines to complete the I/O.
if(m_bUseDMAForTransfer == FALSE)
{
//----- 8. Polling I/O, use our special routines to handle this request
switch(pRequest->TransferClass)
{
case SD_READ:
if(!PollingReceive(pRequest, m_dwNumBytesToTransfer))
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:BusRequestHandler() - PollingReceive() failed\r\n")));
goto TRANSFER_DONE;
}
break;
case SD_WRITE:
if(!PollingTransmit(pRequest, m_dwNumBytesToTransfer))
{
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:BusRequestHandler() - PollingReceive() failed\r\n")));
goto TRANSFER_DONE;
}
break;
}
status = SD_API_STATUS_SUCCESS;
}else
{
//----- 9. For WRITE requests, be sure to copy the write data from the caller's buffer into DMA memory-----
if(pRequest->TransferClass == SD_WRITE)
{
BOOL fNoException;
DEBUGCHK(m_dwNumBytesToTransfer <= MAXIMUM_DMA_TRANSFER_SIZE);
SD_SET_PROC_PERMISSIONS_FROM_REQUEST( pRequest ) {
fNoException = SDPerformSafeCopy( m_pDMABuffer, pRequest->pBlockBuffer, m_dwNumBytesToTransfer );
} SD_RESTORE_PROC_PERMISSIONS();
if (fNoException == FALSE) {
status = SD_API_STATUS_ACCESS_VIOLATION;
goto TRANSFER_DONE;
}
}
//----- 10. DMA I/O, enable the DMA channel -----
Enable_SDIO_DMA_Channel();
//----- 11. Wait for a DMA interrupt -----
// first estimate the maximum DMA transfer time
DWORD dwDelay = m_dwNumBytesToTransfer * m_dwDMATransferTimeoutFactor / ( m_dwClockRate / 2000 );
if( Get_SDI_Bus_Width() != WIDE_BUS_ENABLE )
{
dwDelay *= 4;
}
dwDelay += m_dwDMATransferTimeoutConstant;
// now wait for the interrupt
if(WaitForSingleObject(m_hDMAInterruptEvent, dwDelay) != WAIT_OBJECT_0)
{
DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("TransferIstThread(): Wait Failed!\r\n")));
Stop_SDIO_DMA_Channel();
status = SD_API_STATUS_DATA_TIMEOUT;
goto TRANSFER_DONE;
}
if(m_bDriverShutdown)
{
DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("SDHCD:TransferIstThread(): Thread Exiting\r\n")));
return FALSE;
}
//----- 12. ACK the DMA completion interrupt and stop the DMA channel -----
InterruptDone(m_dwDMASysIntr);
Stop_SDIO_DMA_Channel();
DWORD dwWaitCount = 0;
//----- 13. Wait until the I/O transfer is complete -----
while(!(vm_pSDIReg->SDIDSTA & DATA_TRANSMIT_FINISHED))
{
dwWaitCount++;
if( dwWaitCount > WAIT_TIME )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -