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 + -
显示快捷键?