sdcontrol.c
来自「该BSP是基于PXA270+WINCE的BSP」· C语言 代码 · 共 1,659 行 · 第 1/5 页
C
1,659 行
// reset receive buffer index
receiveBufferIndex = 0;
}
} // while
// check for any left over data
if (receiveBufferIndex) {
// safely copy the data
SDPerformSafeCopy(&pRequest->pBlockBuffer[pRequest->HCParam],
pController->RcvBuffer,
receiveBufferIndex);
// bump the running count
pRequest->HCParam += receiveBufferIndex;
}
} SD_RESTORE_PROC_PERMISSIONS();
}
///////////////////////////////////////////////////////////////////////////////
// HandleTransferDone- Handle transfer done interrupt
// Input: pController - the controller that is interrupting
// fForceTimeout - if true, we reached a timeout during transfer
// Output:
// Return:
// Notes:
///////////////////////////////////////////////////////////////////////////////
VOID HandleTransferDone(PSDH_HARDWARE_CONTEXT pController, BOOL fForceTimeout)
{
PSD_BUS_REQUEST pRequest; // current request
DWORD regValue; // intermediate byte value
ULONG maxBytes; // max bytes
// turn off the transfer done interrupt
TRANSFER_DONE_INTERRUPT_OFF(pController);
// turn off data error interrupt
PROGRAM_DATA_ERROR_INTERRUPT_OFF(pController);
pController->dwControllerIstTimeout = INFINITE;
// get the current request
pRequest = SDHCDGetAndLockCurrentRequest(pController->pHCContext, 0);
// this should never happen because we mark the request as un-cancelable
DEBUG_ASSERT(NULL != pRequest);
if( !pRequest )
{
RX_FIFO_INTERRUPT_OFF(pController);
TX_FIFO_INTERRUPT_OFF(pController);
return;
}
if (TRANSFER_IS_READ(pRequest)) {
// make sure RX fifo interrupt is off
RX_FIFO_INTERRUPT_OFF(pController);
} else if (TRANSFER_IS_WRITE(pRequest)) {
// make sure TX fifo interrupt is off
TX_FIFO_INTERRUPT_OFF(pController);
// can't turn off the clock until the prog done interrupt!
} else {
DEBUG_ASSERT(FALSE);
}
// check the transfer status
regValue = READ_MMC_REGISTER_DWORD(pController, MMC_STAT);
// check for errors
if (regValue & MMC_STAT_FLASH_ERROR) {
ASSERT(0);
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports FLASH ERROR\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_DATA_ERROR);
return;
}
if (regValue & MMC_STAT_SPI_WR_ERROR) {
ASSERT(0);
}
if (regValue & MMC_STAT_RD_STALLED) {
ASSERT(0);
}
if ( ( regValue & MMC_STAT_READ_TIMEOUT ) || fForceTimeout ) {
DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleTransferDoneInterrupt: Read Data TimedOut \n")));
if( !( pController->fClockAlwaysOn ||
( pController->fClockOnIfInterruptsEnabled && pController->fSDIOEnabled ) ) )
{
// turn off the clock
SDClockOff(pController);
}
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports DATA TIMEOUT\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_DATA_TIMEOUT);
return;
} else if (regValue & MMC_STAT_READ_DATA_CRC_ERROR) {
DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleTransferDoneInterrupt: Read Data Contains CRC error \n")));
if( !( pController->fClockAlwaysOn ||
( pController->fClockOnIfInterruptsEnabled && pController->fSDIOEnabled ) ) )
{
// turn off the clock
SDClockOff(pController);
}
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports CRC ERROR\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_CRC_ERROR);
return;
} else if (regValue & MMC_STAT_WRITE_DATA_CRC_ERROR) {
DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleTransferDoneInterrupt: Card received Write Data with CRC error \n")));
if( !( pController->fClockAlwaysOn ||
( pController->fClockOnIfInterruptsEnabled && pController->fSDIOEnabled ) ) )
{
// turn off the clock
SDClockOff(pController);
}
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports CRC ERROR\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_CRC_ERROR);
return;
}
#ifdef DEBUG
ASSERT( pController->fDMATransferInProgress == FALSE );
#endif
if(pController->fDMATransfer)
{
pRequest->HCParam = pRequest->NumBlocks * pRequest->BlockSize;
}
if (TRANSFER_IS_READ(pRequest)) {
if( pController->fDMATransfer ) {
if( pController->fDMAUsingDriverBuffer )
{
// copy data from our DMA buffer into client buffer
DWORD oldDmaBufferPermissions = SetProcPermissions( pRequest->CurrentPermissions );
if( !SDPerformSafeCopy(pRequest->pBlockBuffer,
pController->pDMABuffer,
pRequest->BlockSize * pRequest->NumBlocks) )
{
SetProcPermissions(oldDmaBufferPermissions);
ASSERT(0);
DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleTransferDoneInterrupt: Access Violation\n")));
if( !( pController->fClockAlwaysOn ||
( pController->fClockOnIfInterruptsEnabled && pController->fSDIOEnabled ) ) )
{
// turn off the clock
SDClockOff(pController);
}
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports Access Violation\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_ACCESS_VIOLATION);
return;
}
SetProcPermissions(oldDmaBufferPermissions);
}
} else {
// why are we doing this here? If the remaining read data is less than a Fifo's worth (32)
// we won't get the RX Fifo Read Request interrupt because the fifo won't be full.
// also even if it is full or if this isn't the case the TRANSFER_DONE bit seems to mask it out
// anyways this prevents the problem where there are bytes stuck in the Fifo
maxBytes = pRequest->NumBlocks * pRequest->BlockSize;
if (pRequest->HCParam < maxBytes) {
DbgPrintZo(SDH_RECEIVE_ZONE, (TEXT("HandleTransferDoneInterrupt: Fifo contains remaining data, Max: %d, current count %d \n"),
maxBytes, pRequest->HCParam));
// get the remaining bytes out of the FIFO
EmptyReceiveFifo(pController,
pRequest,
(maxBytes - pRequest->HCParam),
maxBytes);
}
}
SetCurrentState(pController, ReadDataDone);
if( !( pController->fClockAlwaysOn ||
( pController->fClockOnIfInterruptsEnabled && pController->fSDIOEnabled ) ) )
{
// now it is safe to turn off the clock
SDClockOff(pController);
}
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("Bytes read: [%S]\n"), HexDisplay( pRequest->pBlockBuffer, TRANSFER_SIZE(pRequest) ) ) );
}
if (TRANSFER_IS_WRITE(pRequest)) {
if (!IS_PROGRAM_DONE(pController)) {
SetCurrentState(pController, ProgramWait);
// turn on programming done interrupt
PROGRAM_DONE_INTERRUPT_ON(pController);
//Sleep(500);
// check to see if programming is finished
if (!IS_PROGRAM_DONE(pController)) {
DbgPrintZo(SDH_TRANSMIT_ZONE, (TEXT("HandleTransferDoneInterrupt: Programming Not Complete \n")));
}
// if we wait on the programming done interrupt this could
// go on forever because now it is up to the memory card,
// we may have to make this request cancelable at this point
return;
}
}
DEBUG_ASSERT((pRequest->HCParam >= (pRequest->NumBlocks * pRequest->BlockSize)));
// complete the request
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports Data Transfer Completed\n")));
if (TRANSFER_IS_READ(pRequest)) {
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("Bytes read: [%S]\n"), HexDisplay( pRequest->pBlockBuffer, TRANSFER_SIZE(pRequest) ) ) );
}
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_SUCCESS);
}
///////////////////////////////////////////////////////////////////////////////
// SDLoadXmitFifo - load the transmit fifo
// Input: pController - the controler
// pRequest - the request
// Output:
// Return: returns TRUE if the request has been fullfilled
// Notes:
///////////////////////////////////////////////////////////////////////////////
BOOL SDLoadXmitFifo(PSDH_HARDWARE_CONTEXT pController, PSD_BUS_REQUEST pRequest)
{
DWORD maxBytes; // max bytes
ULONG remainingBytes; // remaining bytes in the transfer
DWORD ii;
volatile UCHAR *pMMC_TX_Fifo = (volatile UCHAR *)&(pController->pSDMMCRegisters->txfifo);
volatile DWORD *pMMC_TX_FifoDW = (volatile DWORD *)&(pController->pSDMMCRegisters->txfifo);
// precalc
maxBytes = pRequest->NumBlocks * pRequest->BlockSize;
DbgPrintZo(SDH_TRANSMIT_ZONE, (TEXT("SDLoadXmitFifo: Current %d \n"),pRequest->HCParam));
// make sure the partial full flag is cleared
TX_BUFFER_PARTIAL_NOT_FULL(pController);
// according to the spec the TX Fifo Empty interrupt asserts once when the fifo is
// empty
if ((maxBytes - pRequest->HCParam) >= (LONG)MMC_TXFIFO_SIZE) {
// because the remaining bytes is greater than or equal to the fifo size,
// the Tx Fifo better be empty according to Intel's spec!
// DEBUG_ASSERT(TX_FIFO_EMPTY(pController)); @todo
}
if( !IsCardPresent() )
{
DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("SDLoadXmitFifo: Card ejected!\n")));
return TRUE;
}
// we are touching the block buffer, we must set the process permissions
SD_SET_PROC_PERMISSIONS_FROM_REQUEST(pRequest) {
// figure out how much to prefetch from the user
// buffer safely
remainingBytes = maxBytes - pRequest->HCParam;
if (remainingBytes > MMC_TXFIFO_SIZE) {
// fix it
remainingBytes = MMC_TXFIFO_SIZE;
}
// perform the safe copy
SDPerformSafeCopy(pController->XmitBuffer,
&pRequest->pBlockBuffer[pRequest->HCParam],
remainingBytes);
// according to the spec (15.2.8.3) the TX Fifo interrupt asserts for every empty fifo
// (32 bytes)
// so we write a Fifo's worth, as per spec
ii = 0;
while( remainingBytes > 0 )
{
if( remainingBytes >= 4 )
{
// transfer bytes to the fifo from the safe buffer
*pMMC_TX_FifoDW = *((DWORD*)&(pController->XmitBuffer[ii]));
remainingBytes-=4;
ii+=4;
}
else
{
// transfer bytes to the fifo from the safe buffer
*pMMC_TX_Fifo = pController->XmitBuffer[ii];
remainingBytes--;
ii++;
}
} // while
pRequest->HCParam += ii;
} SD_RESTORE_PROC_PERMISSIONS();
// check for a partial buffer
if (ii < MMC_TXFIFO_SIZE) {
TX_BUFFER_PARTIAL_FULL(pController);
}
DbgPrintZo(SDH_TRANSMIT_ZONE, (TEXT("SDLoadXmitFifo: New Current %d \n"),pRequest->HCParam));
// see
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?