sdcontrol.c
来自「pxa27x library for windows ce 5.0」· C语言 代码 · 共 1,690 行 · 第 1/5 页
C
1,690 行
// 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 = READ_MMC_REGISTER_DWORD(pController, MMC_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_FLASH_ERROR) {
ASSERT(0);
}
if (statRegister & MMC_STAT_SPI_WR_ERROR) {
ASSERT(0);
}
if (statRegister & MMC_STAT_RD_STALLED) {
ASSERT(0);
}
if (statRegister & MMC_STAT_RESPONSE_TIMEOUT) {
regValue = READ_MMC_REGISTER_DWORD(pController, MMC_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 = READ_MMC_REGISTER_DWORD(pController, MMC_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;
}
if (NoResponse != pRequest->CommandResponse.ResponseType) {
// read in the response words from the response fifo.
for (ii = startingOffset; ii >= 0; ii--) {
// read from the fifo
responseBuffer[ii] = (USHORT)(READ_MMC_REGISTER_DWORD(pController, MMC_RES));
}
if (ResponseR2 == pRequest->CommandResponse.ResponseType) {
// since the response Fifo is only 16 bytes, the R2 response which is normally 17 bytes
// gets crammed into 16 bits, this offset the whole R2 response by 1 byte so when
// copy the data to the response buffer, bump over the place holder for the CRC
memcpy(&pRequest->CommandResponse.ResponseBuffer[1],
responseBuffer,
(sizeof(USHORT)) * (startingOffset + 1));
} else {
// all other responses are nicely aligned to 6 bytes, the CRC value in the last
// dword is not set, but we copy it anyways to the response buffer
memcpy(pRequest->CommandResponse.ResponseBuffer,
responseBuffer,
(sizeof(USHORT)) * (startingOffset + 1));
}
}
// check for command/response only
if (SD_COMMAND == pRequest->TransferClass) {
// check to see if this request was a response with busy
if (ResponseR1b == pRequest->CommandResponse.ResponseType) {
while( ( !( statRegister & MMC_STAT_PROGRAM_DONE ) ) &&
( !( pController->DriverShutdown ) ) &&
IsCardPresent() )
{
statRegister = READ_MMC_REGISTER_DWORD(pController, MMC_STAT);
}
}
if( !( pController->fClockAlwaysOn ||
( pController->fClockOnIfInterruptsEnabled && pController->fSDIOEnabled ) ) )
{
// complete the current request here, there's no data phase
// turn off the clock
SDClockOff(pController);
}
SetCurrentState(pController, CommandComplete);
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt reports Bus Request Completed\n")));
SDHCDIndicateBusRequestComplete(pController->pHCContext,
pRequest ,
SD_API_STATUS_SUCCESS);
} else {
if (TRANSFER_IS_READ(pRequest)){
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt starting READ TRANSFER of %d blocks of %d bytes\n"), pRequest->NumBlocks, pRequest->BlockSize ));
// turn on RX Fifo interrupts
RX_FIFO_INTERRUPT_ON(pController);
SetCurrentState(pController, ReadDataTransfer);
// turn on the transfer done interrupt to check for timeout on reads
// the receive handler will turn this off after getting the first byte
TRANSFER_DONE_INTERRUPT_ON(pController);
} else {
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("HandleEndCommandInterrupt starting WRITE TRANSFER of %d blocks of %d bytes\n"), pRequest->NumBlocks, pRequest->BlockSize ));
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("Bytes wrtn: [%S]\n"), HexDisplay( pRequest->pBlockBuffer, TRANSFER_SIZE(pRequest) )) );
SetCurrentState(pController, WriteDataTransfer);
// turn on Fifo interrupts
TX_FIFO_INTERRUPT_ON(pController);
// turn on transfer interrupts
TRANSFER_DONE_INTERRUPT_ON(pController);
SDLoadXmitFifo(pController, pRequest);
}
}
}
///////////////////////////////////////////////////////////////////////////////
// HandleSDIOInterrupt - Handle SDIO interrupt
// Input: pController - the controller that is interrupting
// Output:
// Return:
// Notes:
///////////////////////////////////////////////////////////////////////////////
VOID HandleSDIOInterrupt(PSDH_HARDWARE_CONTEXT pHCDevice)
{
ACQUIRE_LOCK(pHCDevice);
if( IsCardPresent( pHCDevice ) && pHCDevice->DevicePresent )
{
// disable the SDIO interrupt
SDIO_INTERRUPT_OFF(pHCDevice);
// indicate that the card is interrupting
DbgPrintZo(SDH_SDBUS_INTERACTION_ZONE, (TEXT("Got SDIO Interrupt\n")));
SDHCDIndicateSlotStateChange(pHCDevice->pHCContext,
0,
DeviceInterrupting);
}
RELEASE_LOCK(pHCDevice);
}
///////////////////////////////////////////////////////////////////////////////
// GetMMCInterrupts - Get MMC interrupts
// Input: pHCDevice - the controller
// Output:
// Return: bit mask of the interrupts
// Notes:
///////////////////////////////////////////////////////////////////////////////
DWORD GetMMCInterrupts(PSDH_HARDWARE_CONTEXT pHCDevice)
{
DWORD intr;
DWORD interrupts; // current interrupts
DWORD interruptMask; // interrupt mask
DWORD stat;
// get interrupts
intr = READ_MMC_REGISTER_DWORD(pHCDevice, MMC_IREG)
& MMC_IREG_INTERRUPTS;
// get the interrupt masks so we know which ones we don't care about
// the handlers will turn off (mask) interrupts
interruptMask = (~(READ_MMC_REGISTER_DWORD(pHCDevice, MMC_IMASK)))
& MMC_IREG_INTERRUPTS;
// mask it
interrupts = intr & interruptMask;
stat = pHCDevice->pSDMMCRegisters->stat;
if( pHCDevice->fSDIOEnabled )
{
DbgPrintZo(SDH_INTERRUPT_ZONE,
(TEXT("S=%04X I=%04X M=%04X R=%04X\n"),
stat, intr, interruptMask, interrupts));
}
return interrupts;
}
///////////////////////////////////////////////////////////////////////////////
// SDControllerIstThread - IST thread for MMC Controller driver
// Input: pHCDevice - the controller instance
// Output:
// Return: Thread exit code
// Notes:
///////////////////////////////////////////////////////////////////////////////
DWORD SDControllerIstThread(PSDH_HARDWARE_CONTEXT pHCDevice)
{
DWORD waitStatus; // wait status
DWORD interrupts; // current interrupts
if (!CeSetThreadPriority(GetCurrentThread(),
pHCDevice->ControllerIstThreadPriority)) {
DbgPrintZo(SDCARD_ZONE_WARN,
(TEXT("SDControllerIstThread: warning, failed to set CEThreadPriority \n")));
}
while(1) {
waitStatus = WaitForSingleObject(pHCDevice->hControllerInterruptEvent, INFINITE);
if (WAIT_OBJECT_0 != waitStatus) {
DbgPrintZo(SDCARD_ZONE_WARN,
(TEXT("SDControllerIstThread: Wait Failed! 0x%08X \n"), waitStatus));
// bail out
return 0;
}
if (pHCDevice->DriverShutdown) {
DbgPrintZo(1, (TEXT("SDControllerIstThread: Thread Exiting\n")));
return 0;
}
DbgPrintZo(SDH_INTERRUPT_ZONE, (TEXT("SDIst+++++++++++++ \n")));
// loop until all interrupts are serviced
while (interrupts = GetMMCInterrupts(pHCDevice)) {
DbgPrintZo(SDH_INTERRUPT_ZONE,
(TEXT("SDControllerIstThread: Controller Interrupt: 0x%08X \n"),interrupts));
if (interrupts & MMC_IREG_TINT) {
// no one should be turning this on
DEBUG_ASSERT(FALSE);
}
if (interrupts & MMC_IREG_DAT_ERR) {
// no one should be turning this on
DEBUG_ASSERT(FALSE);
}
if (interrupts & MMC_IREG_RES_ERR) {
// no one should be turning this on
DEBUG_ASSERT(FALSE);
}
if (interrupts & MMC_IREG_RD_STALLED) {
// no one should be turning this on
DEBUG_ASSERT(FALSE);
}
if (interrupts & MMC_IREG_SDIO_SUSPEND_ACK) {
// no one should be turning this on
DEBUG_ASSERT(FALSE);
}
if (interrupts & MMC_IREG_CLOCK_IS_OFF) {
// no one should be turning this on
DEBUG_ASSERT(FALSE);
// mask the interrupt
CLOCK_OFF_INTERRUPT_OFF(pHCDevice);
}
if (interrupts & MMC_IREG_END_CMD) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?