📄 sdcontrol.c
字号:
SDClockOff(pController);
}
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleTransferDone reports CRC ERROR\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_CRC_ERROR);
return;
}
if (TRANSFER_IS_READ(pRequest)) {
// 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 ii = 0; // loop variable
ULONG remainingBytes; // remaining bytes in the transfer
volatile UCHAR *pMMC_TX_Fifo = (volatile UCHAR *)&(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
pController->pSDMMCRegisters->PRTBUF = 0;
// 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
}
// 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
for (ii = 0; ii < remainingBytes; ii++) {
if( !IsCardPresent() )
{
DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("SDLoadXmitFifo: Card ejected!\n")));
break;
}
// transfer bytes to the fifo from the safe buffer
*pMMC_TX_Fifo = pController->XmitBuffer[ii];
pRequest->HCParam++;
// check to see if we've read enough
if (pRequest->HCParam >= maxBytes) {
break;
}
}
// check for a partial buffer
if (ii < MMC_TXFIFO_SIZE) {
pController->pSDMMCRegisters->PRTBUF = MMC_PRTBUF_BUFFER_PARTIAL_FULL;
}
DbgPrintZo(SDH_TRANSMIT_ZONE, (TEXT("SDLoadXmitFifo: New Current %d \n"),pRequest->HCParam));
// see if we are done
if (pRequest->HCParam >= maxBytes) {
return TRUE;
}
return FALSE;
}
///////////////////////////////////////////////////////////////////////////////
// HandleXmitInterrupt - handle the Xmit Fifo Empty interrupt
// Input: pController - the controler
// Output:
// Return:
// Notes:
///////////////////////////////////////////////////////////////////////////////
VOID HandleXmitInterrupt(PSDH_HARDWARE_CONTEXT pController)
{
PSD_BUS_REQUEST pRequest; // current request
// 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 (SDLoadXmitFifo(pController, pRequest)) {
// the request is complete
// turn off the Fifo Interrupts
TX_FIFO_INTERRUPT_OFF(pController);
SetCurrentState(pController, WriteDataTransferDone);
}
// now we need to wait for the controller to transmit (transfer done) and the card
// to complete programming (program done)
// if the transfer is done or programming is done before we go back into the interrupt wait
// the interrupt bit will be set and the IST loop will handle the transfer done in this same thread
}
///////////////////////////////////////////////////////////////////////////////
// HandleReceiveInterrupt - Handle recieve data interrupt
// Input: pController - the controller that is interrupting
// Output:
// Return:
// Notes:
///////////////////////////////////////////////////////////////////////////////
VOID HandleReceiveInterrupt(PSDH_HARDWARE_CONTEXT pController)
{
PSD_BUS_REQUEST pRequest; // current request
DWORD maxBytes; // max bytes
ULONG ii = 0; // loop variable
// 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);
maxBytes = pRequest->NumBlocks * pRequest->BlockSize;
DbgPrintZo(SDH_RECEIVE_ZONE, (TEXT("HandleReceiveInterrupt: Max: %d, Current %d \n"),
maxBytes, pRequest->HCParam));
// according to the spec (15.2.8.2) the RX Fifo interrupt asserts for every 32 bytes and
// remains asserted until the RX fifo is empty, once it is empty
// the interrupt req resets and won't assert until 32 more bytes are received
// or until the transfer is complete and their is a partial Fifo
if ((maxBytes - pRequest->HCParam) >= (LONG)MMC_RXFIFO_SIZE) {
// because the remaining bytes is greater than or equal to the fifo size,
// the fifo better be full as per Intel spec!
// DEBUG_ASSERT(RX_FIFO_FULL(pController)); @todo
}
// read a Fifo's worth, as per spec
EmptyReceiveFifo(pController, pRequest, MMC_RXFIFO_SIZE, maxBytes);
DbgPrintZo(SDH_RECEIVE_ZONE, (TEXT("HandleReceiveInterrupt: New Current %d \n"),pRequest->HCParam));
// see if we are done
if (pRequest->HCParam >= maxBytes) {
DbgPrintZo(SDH_RECEIVE_ZONE, (TEXT("HandleReceiveInterrupt: Data Transfer Completing waiting for TRANS_DONE..\n")));
// if we are finished, turn off the RX Fifo request interrupt
RX_FIFO_INTERRUPT_OFF(pController);
SetCurrentState(pController, ReadDataTransferDone);
// now we need to wait for the controller to perform the CRC check and issue trailing clocks (transfer done)
// if the transfer is done, the interrupt bit will be set and the IST loop will
// handle the transfer done in this same thread
}
// we could mark the request as cancelable again...
}
///////////////////////////////////////////////////////////////////////////////
// HandleEndCommandInterrupt - Handle End of Command Interrupt
// Input: pController - the controller that is interrupting
// Output:
// Notes:
///////////////////////////////////////////////////////////////////////////////
VOID HandleEndCommandInterrupt(PSDH_HARDWARE_CONTEXT pController)
{
DWORD statRegister; // status register
PSD_BUS_REQUEST pRequest; // the request to complete
DWORD regValue; // intermediate reg value
LONG ii; // loop variable
LONG startingOffset; // starting offset in response buffer
USHORT responseBuffer[SDH_RESPONSE_FIFO_DEPTH]; // response buffer
// 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);
// get the stat register
statRegister = pController->pSDMMCRegisters->STAT;
// mask the END_CMD interrupt, the command is complete , however
// reading the STAT register doesn't clear the interrupt
// we need to just mask this interrupt out
END_CMD_INTERRUPT_OFF(pController);
if (statRegister & MMC_STAT_RESPONSE_TIMEOUT) {
regValue = pController->pSDMMCRegisters->CMD;
regValue &= 0x3F;
DbgPrintZo(SDCARD_ZONE_WARN, (TEXT("HandleEndCommandInterrupt: response for command %d , timed - out \n"),regValue));
if( !( pController->fClockAlwaysOn ||
( pController->fClockOnIfInterruptsEnabled && pController->fSDIOEnabled ) ) )
{
// turn off the clock
SDClockOff(pController);
}
// complete the current request with a timeout
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt reports RESPONSE TIMEOUT\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_RESPONSE_TIMEOUT);
return;
}
if (statRegister & MMC_STAT_RESPONSE_CRC_ERROR) {
regValue = pController->pSDMMCRegisters->CMD;
regValue &= 0x3F;
if( !( pController->fClockAlwaysOn ||
( pController->fClockOnIfInterruptsEnabled && pController->fSDIOEnabled ) ) )
{
// turn off the clock
SDClockOff(pController);
}
DbgPrintZo(SDCARD_ZONE_ERROR, (TEXT("HandleEndCommandInterrupt: response for command %d , contains a CRC error \n"), regValue));
// complete the current request with a CRC error status
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt reports CRC ERROR\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_CRC_ERROR);
return;
}
if (NoResponse == pRequest->CommandResponse.ResponseType) {
startingOffset = -1;
} else if (ResponseR2 == pRequest->CommandResponse.ResponseType) {
// 8 words - 128 bits
startingOffset = SDH_RESPONSE_FIFO_DEPTH - 1;
} else {
// 3 WORDS - 48 bits
startingOffset = 2;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -