Windows CE SDHC驱动简析(2)-CSDIOControllerBase类(基于WinCE5.0 SMDK2410 BSP的SDHC驱动)

接下来我们来看看CSDIOControllerBase类,该类实现了主控制器驱动的硬件实现,定义了很多成员变量和函数,如有错误,欢迎指正.
CSDIOControllerBase原型如下:
class CSDIOControllerBase { public: explicit CSDIOControllerBase( PSDCARD_HC_CONTEXT pHCContext ); virtual ~CSDIOControllerBase(); PSDCARD_HC_CONTEXT GetHostContext() const; virtual BOOL InterpretCapabilities( LPCTSTR pszRegistryPath ); void OnPowerUp(); void OnPowerDown(); void PreDeinit(); protected: // override to customize for specific hardware virtual BOOL InitializeHardware( BOOL bOnPowerUp = FALSE ) = 0; virtual void DeinitializeHardware( BOOL bOnPowerDown = FALSE ) = 0; virtual BOOL CustomSetup( LPCTSTR pszRegistryPath ) = 0; virtual BOOL IsCardWriteProtected() = 0; virtual BOOL IsCardPresent() = 0; protected: volatile S3C2410X_SDI_REG *vm_pSDIReg; // pointer to the SDI special registers volatile S3C2410X_IOPORT_REG *vm_pIOPreg; // pointer to the GPIO control registers volatile S3C2410X_CLKPWR_REG *vm_pCLKPWR; // pointer to the clock control register volatile S3C2410X_DMA_REG *vm_pDMAreg; // pointer to the DMA special registers DWORD m_dwSDIOIrq; // SDIO IRQ DWORD m_dwSDIOSysIntr; // SDIO SysIntr PBYTE m_pDMABuffer; // pointer to buffers used for DMA transfers PHYSICAL_ADDRESS m_pDMABufferPhys; // physical address of the SMA buffer DWORD m_dwDMAChannel; // DMA channel to use for data transfers DWORD m_dwDMAIrq; // DMA IRQ DWORD m_dwDMASysIntr; // DMA SysIntr DWORD m_dwPollingTimeout; // card detect thread polling timeout char m_chCardDetectGPIO; // GPIO used for card detection DWORD m_dwCardDetectMask; DWORD m_dwCardDetectFlag; DWORD m_dwCardDetectControlMask; DWORD m_dwCardDetectControlFlag; DWORD m_dwCardDetectPullupMask; DWORD m_dwCardDetectPullupFlag; char m_chCardReadWriteGPIO; // GPIO used for card read/write detection DWORD m_dwCardReadWriteMask; DWORD m_dwCardReadWriteFlag; DWORD m_dwCardReadWriteControlMask; DWORD m_dwCardReadWriteControlFlag; DWORD m_dwCardReadWritePullupMask; DWORD m_dwCardReadWritePullupFlag; PSDCARD_HC_CONTEXT m_pHCContext; // the host controller context HANDLE m_hResponseReceivedEvent; // Used to post command response info asynchronously int m_nCardDetectIstThreadPriority; // controller IST thread priority HANDLE m_hCardInsertInterruptEvent; // card insert/remove interrupt event HANDLE m_hCardInsertInterruptThread; // card insert/remove interrupt event int m_nSDIOIstThreadPriority; // SDIO IST thread priority HANDLE m_hSDIOInterruptEvent; // SDIO Interrupt event HANDLE m_hSDIOInterruptThread; // SDIO Interrupt Thread Event int m_nControllerIstThreadPriority; // controller IST thread priority HANDLE m_hControllerInterruptEvent; // controller interrupt event HANDLE m_hControllerInterruptThread; // controller interrupt thread int m_DMAIstThreadPriority; // DMA IST thread priority HANDLE m_hDMAInterruptEvent; // DMA interrupt event HANDLE m_hDMAInterruptThread; // DMA interrupt thread BOOL m_bReinsertTheCard; // Indicates if a card insertion should be simulated now BOOL m_bUseDMAForTransfer; // Indicates whether DMA is used for I/O requests BOOL m_bDriverShutdown; // controller shutdown CRITICAL_SECTION m_ControllerCriticalSection; // controller critical section BOOL m_bDevicePresent; // indicates if device is present in the slot WCHAR m_rgchRegPath[256]; // reg path SDHCDSTATE m_CurrentState; // current transfer state BOOL m_bSendInitClocks; // indicates if this is the first command sent DWORD m_dwLastTypeOfTransfer; // inidcates the last type of data transfer initiated DWORD m_dwNumBytesToTransfer; // # of bytes that still need to be transferred DWORD m_dwNumBytesUnaligned; // # of bytes from a DWORD-aligned address DWORD m_dwNumBytesExtra; // # of extra bytes in buffer that aren't a multiple of sizeof(DWORD) DWORD m_dwSDIBusWidth; // SD data transfer mode (1 bit or 4 bit) flag DWORD m_dwClockRate; // current clock rate BOOL m_fCardInTheSlot; // TRUE - a card is inserted in the slot, FALSE otherwise BOOL m_fHandleBusyCheckOnCommand38; DWORD m_dwDMATransferTimeoutFactor; DWORD m_dwDMATransferTimeoutConstant; SD_API_STATUS SendCommand(UINT16 Cmd, UINT32 Arg, UINT16 respType, BOOL bDataTransfer); SD_API_STATUS GetCommandResponse(PSD_BUS_REQUEST pRequest); DWORD SetClockRate(DWORD dwClockRate); BOOL IsCardBusy(UINT16 inData); BOOL SetupDmaXfer(PSD_BUS_REQUEST pRequest); BOOL SetupPollingXfer(PSD_BUS_REQUEST pRequest); BOOL PollingTransmit(PSD_BUS_REQUEST pRequest, DWORD dwLen); BOOL PollingReceive(PSD_BUS_REQUEST pRequest, DWORD dwLen); inline void MMC_Hardware_PowerUp(); inline void MMC_Hardware_PowerDown(); inline void Stop_SDI_Hardware(); inline void Set_SDI_Bus_Width_1Bit(); inline void Set_SDI_Bus_Width_4Bit(); inline DWORD Get_SDI_Bus_Width(); inline void Wait_80_SDI_Clock_Cycles(); inline void Start_SDI_Clock(); inline void Stop_SDI_Clock(); inline BOOL Is_SDI_Clock_Running(); inline void Enable_SDIO_Interrupts(); inline void Disable_SDIO_Interrupts(); inline BOOL Is_SDIO_Interrupt_Enabled(); inline void Ack_SDIO_Interrupts(); inline void Enable_SDIO_DMA_Channel(); inline void Disable_SDIO_DMA_Channel(); inline void Stop_SDIO_DMA_Channel(); // thread routines virtual DWORD CardDetectThread(); virtual DWORD IOInterruptIstThread(); virtual DWORD TransferIstThread(); // implementation of the callbacks for the SD Bus driver SD_API_STATUS Deinitialize(); SD_API_STATUS Initialize(); BOOLEAN CancelIoHandler(DWORD dwSlot, PSD_BUS_REQUEST pRequest); SD_API_STATUS BusRequestHandler(DWORD dwSlot, PSD_BUS_REQUEST pRequest); SD_API_STATUS SlotOptionHandler(DWORD dwSlot, SD_SLOT_OPTION_CODE Option, PVOID pData, ULONG OptionSize); // thread start routines static DWORD SD_CardDetectThread(CSDIOControllerBase *pController); static DWORD SD_IOInterruptIstThread(CSDIOControllerBase *pController); static DWORD SD_TransferIstThread(CSDIOControllerBase *pController); // SD Bus driver callback functions static SD_API_STATUS SDHCDDeinitialize(PSDCARD_HC_CONTEXT pHCContext); static SD_API_STATUS SDHCDInitialize(PSDCARD_HC_CONTEXT pHCContext); static BOOLEAN SDHCDCancelIoHandler(PSDCARD_HC_CONTEXT pHCContext, DWORD dwSlot, PSD_BUS_REQUEST pRequest); static SD_API_STATUS SDHCDBusRequestHandler(PSDCARD_HC_CONTEXT pHCContext, DWORD dwSlot, PSD_BUS_REQUEST pRequest); static SD_API_STATUS SDHCDSlotOptionHandler(PSDCARD_HC_CONTEXT pHCContext, DWORD dwSlot, SD_SLOT_OPTION_CODE Option, PVOID pData, ULONG OptionSize); };
其中有几个纯虚函数是由继承类实现的(CSDIOController类,sdiocontroller.cpp)
    virtual BOOL InitializeHardware( BOOL bOnPowerUp = FALSE ) = 0;
    virtual void DeinitializeHardware( BOOL bOnPowerDown = FALSE ) = 0;
    virtual BOOL CustomSetup( LPCTSTR pszRegistryPath ) = 0;
    virtual BOOL IsCardWriteProtected() = 0;
    virtual BOOL IsCardPresent() = 0;
下面我们来一一看看每个成员函数:
1.构造函数CSDIOControllerBase
初始化成员变量,大部分初始化为0或NULL,当前状态m_CurrentState设为Idle
CSDIOControllerBase::CSDIOControllerBase( PSDCARD_HC_CONTEXT pHCContext ) { vm_pSDIReg = NULL; vm_pIOPreg = NULL; vm_pCLKPWR = NULL; vm_pDMAreg = NULL; m_pDMABuffer = NULL; m_dwDMAChannel = 0; m_pHCContext = pHCContext; m_hResponseReceivedEvent = NULL; m_nCardDetectIstThreadPriority = 0; m_hCardInsertInterruptEvent = NULL; m_hCardInsertInterruptThread = NULL; m_nSDIOIstThreadPriority = 0; m_hSDIOInterruptEvent = NULL; m_hSDIOInterruptThread = NULL; m_nControllerIstThreadPriority = 0; m_hControllerInterruptEvent = NULL; m_hControllerInterruptThread = NULL; m_DMAIstThreadPriority = 0; m_hDMAInterruptEvent = NULL; m_hDMAInterruptThread = NULL; m_bUseDMAForTransfer = FALSE; m_bDriverShutdown = FALSE; m_bDevicePresent = FALSE; m_CurrentState = Idle; m_bSendInitClocks = TRUE; m_dwLastTypeOfTransfer = SD_READ; m_dwNumBytesToTransfer = 0; m_dwNumBytesUnaligned = 0; m_dwNumBytesExtra = 0; m_rgchRegPath[0] = 0; m_dwSDIBusWidth = 0; m_bReinsertTheCard = FALSE; m_fHandleBusyCheckOnCommand38 = FALSE; m_dwDMATransferTimeoutFactor = 8; m_dwDMATransferTimeoutConstant = 3000; m_fCardInTheSlot = FALSE; }  
2.~CSDIOControllerBase
未做任何工作.

3.PreDeinit
这个函数被SDH_PreDeinit调用,m_bDriverShutdown为FALSE时调用Deinitialize进行资源释放.
void CSDIOControllerBase::PreDeinit() { if( !m_bDriverShutdown ) { Deinitialize(); } } 
4.Initialize
该函数被SDHCDInitialize调用.
(1)设置crtical section临界访问,然后映射GPIO寄存器空SDI控制器,时钟能源管理寄存器,DMA控制器IO地址空间. 然后分配内存给DMA传输(64KB大小).
接着初始化寄存器
(2)MMC_Hardware_PowerUp设置CLKCON使能SDI PCLK.
(3)设置GPIO寄存器使能SDI功能
(4)SetClockRate设置SDI时钟(100HZ)
(5)设置SDI寄存器模式,little edian,512 bytes per block,设置timeout,reset fifo
(6)创建SD卡检测事件m_hCardInsertInterruptEvent及线程SD_CardDetectThread
(7)创建接收应答事件m_hResponseReceivedEvent
(8)创建IST线程m_hSDIOInterruptThread处理SDIO数据传输中断事件m_hSDIOInterruptEvent,并初始化中断
(9)设置DMA传输中断事件m_hDMAInterruptEvent和线程m_hDMAInterruptThread
(10)调用继承类InitializeHardware函数.
(11)出错处理,调用Deinitialize
SD_API_STATUS CSDIOControllerBase::Initialize() { DEBUGMSG (SDCARD_ZONE_INIT,(TEXT("SDHCDInitialize starts"))); SD_API_STATUS status = SD_API_STATUS_SUCCESS; // intermediate status DWORD threadID; // thread ID InitializeCriticalSection(&m_ControllerCriticalSection); //----- 1. Map the GPIO registers needed to enable the SDI controller ----- vm_pIOPreg = (S3C2410X_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2410X_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS); if (vm_pIOPreg == NULL) { DEBUGMSG (1,(TEXT("GPIO registers not allocated"))); status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } if (!VirtualCopy((PVOID)vm_pIOPreg, (PVOID)(S3C2410X_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2410X_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)) { DEBUGMSG (1,(TEXT("GPIO registers not mapped"))); status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } DEBUGMSG (1,(TEXT("GPIO registers mapped to %x"), vm_pIOPreg)); //----- 2. Map the SDI control registers into the device drivers address space ----- vm_pSDIReg = (S3C2410X_SDI_REG *)VirtualAlloc(0, sizeof(S3C2410X_SDI_REG), MEM_RESERVE, PAGE_NOACCESS); if (vm_pSDIReg == NULL) { DEBUGMSG (1,(TEXT("SDI control registers not allocated/n/r"))); status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } if (!VirtualCopy((PVOID)vm_pSDIReg, (PVOID)(S3C2410X_BASE_REG_PA_SDI >> 8), sizeof(S3C2410X_SDI_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)) { DEBUGMSG (1,(TEXT("SDI control registers not mapped/n/r"))); status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } DEBUGMSG (1,(TEXT("SDI control registers mapped to %x/n/r"), vm_pSDIReg)); vm_pCLKPWR = (S3C2410X_CLKPWR_REG *)VirtualAlloc(0, sizeof(S3C2410X_CLKPWR_REG), MEM_RESERVE, PAGE_NOACCESS); if (vm_pCLKPWR == NULL) { DEBUGMSG (1,(TEXT("Clock & Power Management Special Register not allocated/n/r"))); status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } if (!VirtualCopy((PVOID)vm_pCLKPWR, (PVOID)(S3C2410X_BASE_REG_PA_CLOCK_POWER >> 8), sizeof(S3C2410X_CLKPWR_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)) { DEBUGMSG (1,(TEXT("Clock & Power Management Special Register not mapped/n/r"))); goto INIT_ERROR; } DEBUGMSG (1,(TEXT("Clock & Power Management Special Register mapped to %x/n/r"), vm_pCLKPWR)); if( m_dwDMAChannel != 0xffffffff ) { //----- 3. Map the DMA control registers used for SDI data transfers ----- vm_pDMAreg = (S3C2410X_DMA_REG *)VirtualAlloc(0, sizeof(S3C2410X_DMA_REG), MEM_RESERVE, PAGE_NOACCESS); if (vm_pDMAreg == NULL) { DEBUGMSG (1,(TEXT("DMA Register not allocated/n/r"))); status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } if (!VirtualCopy((PVOID)vm_pDMAreg, (PVOID)(S3C2410X_BASE_REG_PA_DMA >> 8), sizeof(S3C2410X_DMA_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)) { DEBUGMSG (1,(TEXT("DMA Register not mapped/n/r"))); status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } DEBUGMSG (1,(TEXT("DMA Register mapped to %x/n/r"), vm_pDMAreg)); //----- 4. Allocate a block of memory for DMA transfers ----- DMA_ADAPTER_OBJECT dmaAdapter; dmaAdapter.ObjectSize = sizeof(dmaAdapter); dmaAdapter.InterfaceType = Internal; dmaAdapter.BusNumber = 0; m_pDMABuffer = (PBYTE)HalAllocateCommonBuffer( &dmaAdapter, MAXIMUM_DMA_TRANSFER_SIZE, &m_pDMABufferPhys, FALSE ); if( m_pDMABuffer == NULL ) { RETAILMSG(1, (TEXT("SHCDriver: - Unable to allocate memory for DMA buffers!/r/n"))); status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } } // Supply the clock to the SDI controller MMC_Hardware_PowerUp(); //----- 6. Configure the GPIO lines for SDI mode and enable the pullup resistor ----- vm_pIOPreg->GPEUP &= 0xF83F; vm_pIOPreg->GPECON |= 0x2AA800; //----- 7. Set the SD/SDI controller to some reasonable default values ----- SetClockRate(SD_DEFAULT_CARD_ID_CLOCK_RATE); // 100Khz vm_pSDIReg->SDICON |= LITTLE_ENDIAN_BYTE_ORDER; // Windows CE is always Little Endian. vm_pSDIReg->SDICON |= RESET_FIFO; // Reset the FIFO vm_pSDIReg->SDIBSIZE = BYTES_PER_SECTOR; vm_pSDIReg->SDIDTIMER = MAX_DATABUSY_TIMEOUT; // Data/busy timeout //----- 8. Setup the thread for detecting card insertion/deletion ----- m_hCardInsertInterruptEvent = CreateEvent(NULL, FALSE, FALSE,NULL); if(NULL == m_hCardInsertInterruptEvent) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } m_bDevicePresent = FALSE; m_hCardInsertInterruptThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SD_CardDetectThread, this, 0, &threadID); if(NULL == m_hCardInsertInterruptThread) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } //----- 9 . Setup an event used for signaling our response thread ----- m_hResponseReceivedEvent = CreateEvent(NULL, FALSE, FALSE,NULL); if(NULL == m_hResponseReceivedEvent) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } //----- 10. Setup the IST for handling SDIO data transfer interrupts ----- m_hSDIOInterruptEvent = CreateEvent(NULL, FALSE, FALSE,NULL); if(NULL == m_hSDIOInterruptEvent) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } // initialize the card insertion interrupt event if(!InterruptInitialize (m_dwSDIOSysIntr, m_hSDIOInterruptEvent, NULL, 0)) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } m_hSDIOInterruptThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SD_IOInterruptIstThread, this, 0, &threadID); if(NULL == m_hSDIOInterruptThread) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } //----- 11. Setup the interrupt event for handling SDIO DMA data transfers ----- m_hDMAInterruptEvent = CreateEvent(NULL, FALSE, FALSE,NULL); if(NULL == m_hDMAInterruptEvent) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } // initialize the dma transfer interrupt event if(!InterruptInitialize (m_dwDMASysIntr, m_hDMAInterruptEvent, NULL, 0)) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } m_hDMAInterruptThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SD_TransferIstThread, this, 0, &threadID); if(NULL == m_hDMAInterruptThread) { status = SD_API_STATUS_INSUFFICIENT_RESOURCES; goto INIT_ERROR; } m_dwLastTypeOfTransfer = SD_READ; m_bUseDMAForTransfer = FALSE; if( !InitializeHardware() ) { DEBUGMSG (1,(TEXT("InitializeHardware failed!/n/r"))); status = SD_API_STATUS_UNSUCCESSFUL; goto INIT_ERROR; } INIT_ERROR: if(!SD_API_SUCCESS(status)) { Deinitialize(); } DEBUGMSG (SDCARD_ZONE_INIT,(TEXT("SDHCDInitialize ends"))); return status; }
5.Deinitialize
Deinitialize用来关闭Initialize创建的事件IST线程,释放DMA buffer,关闭SDI power等
SD_API_STATUS CSDIOControllerBase::Deinitialize() { DEBUGMSG (SDCARD_ZONE_INIT,(TEXT("SDHCDDeinitialize starts"))); //----- 1. Set the controller state to "shutdown" ----- m_bDriverShutdown = TRUE; //----- 2. Disable and cleanup the ISTs/events ------ InterruptDisable (m_dwSDIOSysIntr); SetEvent(m_hResponseReceivedEvent); InterruptDisable (m_dwDMASysIntr); if(NULL != m_hResponseReceivedEvent) { CloseHandle(m_hResponseReceivedEvent); m_hResponseReceivedEvent = NULL; } if(NULL != m_hSDIOInterruptThread) { WaitForSingleObject(m_hSDIOInterruptThread, INFINITE); CloseHandle(m_hSDIOInterruptThread); m_hSDIOInterruptThread = NULL; } if(NULL != m_hSDIOInterruptEvent) { CloseHandle(m_hSDIOInterruptEvent); m_hSDIOInterruptEvent = NULL; } if(NULL != m_hDMAInterruptThread) { WaitForSingleObject(m_hDMAInterruptThread, INFINITE); CloseHandle(m_hDMAInterruptThread); m_hDMAInterruptThread = NULL; } if(NULL != m_hDMAInterruptEvent) { CloseHandle(m_hDMAInterruptEvent); m_hDMAInterruptEvent = NULL; } if(NULL != m_hCardInsertInterruptThread) { WaitForSingleObject(m_hCardInsertInterruptThread, INFINITE); CloseHandle(m_hCardInsertInterruptThread); m_hCardInsertInterruptThread = NULL; } if(NULL != m_hCardInsertInterruptEvent) { CloseHandle(m_hCardInsertInterruptEvent); m_hCardInsertInterruptEvent = NULL; } if( m_dwDMAChannel != 0xffffffff ) { //----- 3. Free the DMA memory ----- HalFreeCommonBuffer( NULL, 0, m_pDMABufferPhys, m_pDMABuffer, FALSE ); } //----- 4. Close the handle to the utility driver (used for fast driver-->driver calling ----- MMC_Hardware_PowerDown(); DeleteCriticalSection(&m_ControllerCriticalSection); DEBUGMSG (SDCARD_ZONE_INIT,(TEXT("SDHCDDeinitialize ends"))); return SD_API_STATUS_SUCCESS; }
6.CancelIoHandler
CancelIoHandler被SDHCDCancelIoHandler调用.首先调用Stop_SDI_Hardware设置SDIDCON强制停止数据传输.调用SDHCDReleaseHCLock释放lock,最后调用SDHCDIndicateBusRequestComplete使用Cancel状态(SD_API_STATUS_CANCELED)来完成Bus请求.
BOOLEAN CSDIOControllerBase::CancelIoHandler(DWORD dwSlot, PSD_BUS_REQUEST pRequest) { DEBUGMSG (SDCARD_ZONE_FUNC,(TEXT("SDHCDCancelIoHandler starts"))); //--- Stop hardware, cancel the request! Stop_SDI_Hardware(); // release the lock before we complete the request SDHCDReleaseHCLock(m_pHCContext); // complete the request with a cancelled status SDHCDIndicateBusRequestComplete(m_pHCContext, pRequest,SD_API_STATUS_CANCELED); DEBUGMSG (SDCARD_ZONE_FUNC,(TEXT("SDHCDCancelIoHandler ends"))); return TRUE; }
7.SlotOptionHandler
CancelIoHandler被SDHCDSlotOptionHandler调用.Slot选项变化时该函数被调用.
(1)SDHCDSetSlotPower:设置slot power,因为系统一直工作在3.3V,不会变化,这里不做任何处理.
(2)SDHCDSetSlotInterface:设置slot接口模式,根据输入数据(pData)设置4bit还是1bit bus模式,调用SetClockRate设置SDI时钟频率.
(3)SDHCDEnableSDIOInterrupts:调用Enable_SDIO_Interrupts使能SDIO中断.
(4)SDHCDDisableSDIOInterrupts:调用Disable_SDIO_Interrupts禁止SDIO中断.
(5)SDHCDAckSDIOInterrupt:调用Ack_SDIO_Interrupts和InterruptDone(m_dwSDIOSysIntr)确认SDIO中断完成.
(6)SDHCDGetWriteProtectStatus:调用IsCardWriteProtected获得写保护状态.
(7)SDHCDQueryBlockCapability:查询Block性能参数.通过输入参数pData来获得ReadBlockSize,WriteBlockSize并根据设定的最大最小值进行修正.
(8)SDHCDGetSlotInfo:获得特定slot的信息.调用SDHCDSetSlotCapabilities等函数设置slot参数,如电压,时钟频率,上电延时等.
SD_API_STATUS CSDIOControllerBase::SlotOptionHandler(DWORD dwSlot, SD_SLOT_OPTION_CODE Option, PVOID pData, ULONG OptionSize) { DEBUGMSG (SDCARD_ZONE_FUNC,(TEXT("SDHCDSlotOptionHandler starts"))); SD_API_STATUS status = SD_API_STATUS_SUCCESS; // status PSD_HOST_BLOCK_CAPABILITY pBlockCaps; // block capabilities switch(Option) { case SDHCDSetSlotPower: DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDSetSlotPower"))); // Nothing to do because this system only operates at the reported 3.3V break; case SDHCDSetSlotInterface: DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDSetSlotInterface"))); // First set the bus width if(((PSD_CARD_INTERFACE)pData)->InterfaceMode == SD_INTERFACE_SD_4BIT) { Set_SDI_Bus_Width_4Bit(); }else { // Standard (i.e. 1bit) bus width Set_SDI_Bus_Width_1Bit(); } // Next, set the clock rate ((PSD_CARD_INTERFACE)pData)->ClockRate = SetClockRate(((PSD_CARD_INTERFACE)pData)->ClockRate); break; case SDHCDEnableSDIOInterrupts: DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDEnableSDIOInterrupts"))); Enable_SDIO_Interrupts(); break; case SDHCDDisableSDIOInterrupts: DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDDisableSDIOInterrupts"))); Disable_SDIO_Interrupts(); break; case SDHCDAckSDIOInterrupt: DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDAckSDIOInterrupt"))); //----- 2. Clear the SDIO interrupt pending bit ----- Ack_SDIO_Interrupts(); InterruptDone(m_dwSDIOSysIntr); break; case SDHCDGetWriteProtectStatus: DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDGetWriteProtectStatus"))); ((PSD_CARD_INTERFACE)pData)->WriteProtected = IsCardWriteProtected(); break; case SDHCDQueryBlockCapability: DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDQueryBlockCapability"))); pBlockCaps = (PSD_HOST_BLOCK_CAPABILITY)pData; DEBUGMSG(SDCARD_ZONE_INFO, (TEXT("SDHCD:SDHCDSlotOptionHandler() - Read Block Length: %d , Read Blocks: %d/n"), pBlockCaps->ReadBlockSize, pBlockCaps->ReadBlocks)); DEBUGMSG(SDCARD_ZONE_INFO, (TEXT("SDHCD:SDHCDSlotOptionHandler() - Write Block Length: %d , Write Blocks: %d/n"), pBlockCaps->WriteBlockSize, pBlockCaps->WriteBlocks)); pBlockCaps = (PSD_HOST_BLOCK_CAPABILITY)pData; //----- Validate block transfer properties ----- if (pBlockCaps->ReadBlockSize < MINIMUM_BLOCK_TRANSFER_SIZE ) { pBlockCaps->ReadBlockSize = MINIMUM_BLOCK_TRANSFER_SIZE; } if (pBlockCaps->WriteBlockSize < MINIMUM_BLOCK_TRANSFER_SIZE ) { pBlockCaps->WriteBlockSize = MINIMUM_BLOCK_TRANSFER_SIZE; } if (pBlockCaps->ReadBlockSize > MAXIMUM_BLOCK_TRANSFER_SIZE ) { pBlockCaps->ReadBlockSize = MAXIMUM_BLOCK_TRANSFER_SIZE; } if (pBlockCaps->WriteBlockSize > MAXIMUM_BLOCK_TRANSFER_SIZE ) { pBlockCaps->WriteBlockSize = MAXIMUM_BLOCK_TRANSFER_SIZE; } break; case SDHCDGetSlotInfo: DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDGetSlotInfo"))); if( OptionSize != sizeof(SDCARD_HC_SLOT_INFO) || pData == NULL ) { status = SD_API_STATUS_INVALID_PARAMETER; } else { PSDCARD_HC_SLOT_INFO pSlotInfo = (PSDCARD_HC_SLOT_INFO)pData; // set the slot capabilities SDHCDSetSlotCapabilities(pSlotInfo, SD_SLOT_SD_4BIT_CAPABLE | SD_SLOT_SD_1BIT_CAPABLE | SD_SLOT_SDIO_CAPABLE | SD_SLOT_SDIO_INT_DETECT_4BIT_MULTI_BLOCK); SDHCDSetVoltageWindowMask(pSlotInfo, (SD_VDD_WINDOW_3_2_TO_3_3 | SD_VDD_WINDOW_3_3_TO_3_4)); // Set optimal voltage SDHCDSetDesiredSlotVoltage(pSlotInfo, SD_VDD_WINDOW_3_2_TO_3_3); SDHCDSetMaxClockRate(pSlotInfo, MAX_SDI_BUS_TRANSFER_SPEED); // Set power up delay. We handle this in SetVoltage(). SDHCDSetPowerUpDelay(pSlotInfo, 300); } break; default: DEBUGMSG (SDCARD_ZONE_WARN,(TEXT("SDHCDSlotOptionHandler option=SD_API_STATUS_INVALID_PARAMETER"))); status = SD_API_STATUS_INVALID_PARAMETER; } DEBUGMSG (SDCARD_ZONE_FUNC,(TEXT("SDHCDSlotOptionHandler ends"))); return status; }
8.BusRequestHandler
BusRequestHandler被SDHCDBusRequestHandler调用,用来处理总线请求.
首先复位FIFO和状态寄存器,然后使能SDI CLOCK,计算要传输数据大小,判断是否DMA传输以及是否4字节对齐,4字节整数倍来进行DMA传输(SetupDmaXfer)或者轮询IO传输(SetupPollingXfer).
接着判断传输的是单独命令还是命令和数据,第一次传输命令时需延时80个clock周期.SendCommand最后一个参数表示是传输命令(FALSE)还是命令和数据(TRUE).
最后设置设置事件m_hResponseReceivedEvent来通知传输IST命令应答发生.
SD_API_STATUS CSDIOControllerBase::BusRequestHandler(DWORD dwSlot, PSD_BUS_REQUEST pRequest) { DEBUGMSG (SDCARD_ZONE_FUNC,(TEXT("BusRequestHandler starts (CMD:%d)"), pRequest->CommandCode)); SD_API_STATUS status; // Reset FIFO and status registers vm_pSDIReg->SDICON |= RESET_FIFO; 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? ----- // // There are two situations that we need to account for: // // 1) A non-DWORD aligned buffer // 2) A buffer whose "transfer size" isn't a multiple of sizeof(DWORD) // // For the first case, an data-alignment exception will occur if the buffer is // addressed at the non-DWORD aligned address. For the second case, the SDI // controller will pad zeros into the remaining bytes of the last unfilled DWORD. // Practically, this means that the SD Card will get a corrupted data string. // // To handle these two situations, we can simply use our polling I/O routines to // fulfill the I/O request. // if( ( m_dwDMAChannel == 0xffffffff ) || (!IS_BUFFER_DWORD_ALIGNED(pRequest->pBlockBuffer)) || (!IS_BUFFER_SIZE_A_DWORD_MULTPLE(pRequest->BlockSize)) || m_dwNumBytesToTransfer > MAXIMUM_DMA_TRANSFER_SIZE ) { m_bUseDMAForTransfer = FALSE; SetupPollingXfer(pRequest); // Use polling I/O routines for data transfer }else{ 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"))); return status; }
9.TransferIstThread
TransferIstThread被SD_TransferIstThread调用,而SD_TransferIstThread在Initialize中被创建,对应于m_hDMAInterruptThread句柄.这个IST线程用来处理SDIO的DMA通道通信.
首先设置该线程的优先级(从注册表中获得,"DMA_IST_Priority"=dword:96),然后等待m_hResponseReceivedEvent事件的发生,该事件发生后继续运行,否则挂起.
m_hResponseReceivedEvent触发后,如果controller down则线程退出.调用SDHCDGetAndLockCurrentRequest(实现在sdhclib)来获取当前slot的请求,并锁住禁止取消.
然后处理一个特殊情况,SD_CMD_STOP_TRANSMISSION命令在SD_CMD_WRITE_MULTIPLE_BLOCK后发送,需要进行BUSY_CHECK.
如果BusyCheck为true,CommandCode为SD_CMD_ERASE或者CommandCode为SD_CMD_STOP_TRANSMISSION,m_dwLastTypeOfTransfer为SD_WRITE时,需要等待IO传输结束.检查SDIDSTA寄存器BusyFin位,如果为0(busy not finish),则进行等待,并判断超时,IsCardPresent,以及一些错误状态,如果任何一种情况发生,就设置BUSY_CHECKS_FINISH,跳转到TRANSFER_DONE通知BusRequest完成.
如果BUSY_CHECKS_FINISH成立,则准备DMA传输.如果ResponseType为NoResponse,跳转到TRANSFER_DONE.否则调用GetCommandResponse获取CommandResponse状态.如果是命令,直接TRANSFER_DONE.数据传输分两种情况是否使用DMA,m_bUseDMAForTransfer为false,启动IO传输,为true,并判断是SD_WRITE写操作时,复制数据到DMA memory,调用Enable_SDIO_DMA_Channel,启动DMA通道,然后等待DMA完成中断事件m_hDMAInterruptEvent,完成后调用InterruptDone和Stop_SDIO_DMA_Channel通知中断完成并停止DMA通道.然后等待读取SDIDSTA等待data transfer结束.如果是SD_READ,读取从DMA memory放到调用缓存区pBlockBuffer中.
最后停止SDI clock,通知总线请求结束(SDHCDIndicateBusRequestComplete).
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 /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!/n"))); return FALSE; } if(m_bDriverShutdown) { DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("SDHCD:TransferIstThread(): Thread Exiting/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. 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; //----- 4. 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->SDIDSTA & FIFO_FAIL_ERROR)) { vm_pSDIReg->SDIDSTA = BUSY_CHECKS_FINISH | 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; } //----- 5. 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; } } //----- 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!/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/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 ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - timeout waiting for DMA transfer completion!/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->SDIDSTA & FIFO_FAIL_ERROR)) { vm_pSDIReg->SDIDSTA = BUSY_CHECKS_FINISH | FIFO_FAIL_ERROR; DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDHControllerIstThread() - FIFO Error waiting for DMA transfer completion!/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 DMA transfer completion!/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 DMA transfer completion!/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 DMA transfer completion!/r/n"))); status = SD_API_STATUS_DATA_TIMEOUT; goto TRANSFER_DONE; } } vm_pSDIReg->SDIDSTA = DATA_TRANSMIT_FINISHED; //----- 14. For READ requests, be sure to copy the data read from the DMA memory into the caller's buffer ----- if(pRequest->TransferClass == SD_READ) { BOOL fNoException; DEBUGCHK(m_dwNumBytesToTransfer <= MAXIMUM_DMA_TRANSFER_SIZE); SD_SET_PROC_PERMISSIONS_FROM_REQUEST( pRequest ) { fNoException = SDPerformSafeCopy( pRequest->pBlockBuffer, m_pDMABuffer, m_dwNumBytesToTransfer ); } SD_RESTORE_PROC_PERMISSIONS(); if (fNoException == FALSE) { status = SD_API_STATUS_ACCESS_VIOLATION; goto TRANSFER_DONE; } } //----- 15. I/O is complete. Finish the bus request! ----- status = SD_API_STATUS_SUCCESS; } TRANSFER_DONE: if( !( Is_SDIO_Interrupt_Enabled() && ( Get_SDI_Bus_Width() == WIDE_BUS_ENABLE ) ) ) { Stop_SDI_Clock(); } m_CurrentState = CommandComplete; SDHCDIndicateBusRequestComplete(m_pHCContext, pRequest, status); pRequest = NULL; } return TRUE; }
10.IOInterruptIstThread
被SD_IOInterruptIstThread调用,对应于句柄m_hSDIOInterruptThread.同样首先设置线程优先级(从注册表中获取"SDIO_IST_Priority"=dword:97),然后等待m_hSDIOInterruptEvent事件发生,如果事件发生同时卡存在的话,调用SDHCDIndicateSlotStateChange通知总线驱动SD卡中断发生.
DWORD CSDIOControllerBase::IOInterruptIstThread() { if( m_nSDIOIstThreadPriority != 0xffffffff && !CeSetThreadPriority( GetCurrentThread(), m_nSDIOIstThreadPriority ) ) { DEBUGMSG(SDCARD_ZONE_WARN,(TEXT("SDHCDriver:SDIOInterruptIstThread(): warning, failed to set CEThreadPriority /n"))); } for(;;) { //----- 1. Wait for a SDIO interrupt ----- if(WaitForSingleObject(m_hSDIOInterruptEvent, INFINITE) != WAIT_OBJECT_0) { DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("SDHCD:SDIOInterruptIstThread(): Wait Failed!/n"))); return FALSE; } if(m_bDriverShutdown) { DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("SDHCD:SDIOInterruptIstThread(): Thread Exiting/n"))); return FALSE; } if(m_bDevicePresent && IsCardPresent()) { // indicate that the card is interrupting SDHCDIndicateSlotStateChange(m_pHCContext, 0, DeviceInterrupting); } // NOTE: SDHCDIndicateSlotStateChange() is called above to inform the bus driver // that the SDIO card has generated an interrupt. After this notification, the // bus driver will eventually call back SDHCDSlotOptionHandler() to enable/disable // and ACK the SDIO interrupt as necessary. Consequently, we DO NOT acknowledge // the interrupt here... } }
11.CardDetectThread
被SD_CardDetectThread调用.首先设置线程优先级(从注册表中获取"CardDetect_Thread_Priority"=dword:98"),然后等待m_hCardInsertInterruptEvent事件,调用IsCardPresent监测卡是否插入.如果卡拔出,调用SDHCDIndicateSlotStateChange通知DeviceEjected,否则卡插入,进行SDI寄存器初始化,设置clock rate(100KHz),启动SDI clock,调用SDHCDIndicateSlotStateChange通知DeviceInserted.
DWORD CSDIOControllerBase::CardDetectThread() { BOOL bSlotStateChanged = FALSE; DWORD dwWaitResult = WAIT_TIMEOUT; if( m_nCardDetectIstThreadPriority != 0xffffffff && !CeSetThreadPriority( GetCurrentThread(), m_nCardDetectIstThreadPriority ) ) { DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("SDHCDriver:CardDetectThread(): warning, failed to set CEThreadPriority /n"))); } for(;;) { //----- 1. Wait for the next insertion/removal interrupt ----- dwWaitResult = WaitForSingleObject(m_hCardInsertInterruptEvent, m_dwPollingTimeout); if(m_bDriverShutdown) { DEBUGMSG(SDCARD_ZONE_WARN, (TEXT("SDHCardDetectIstThread: Thread Exiting/n"))); return FALSE; } // Test if a card is present if( IsCardPresent() == m_bDevicePresent ) { bSlotStateChanged = FALSE; } else { bSlotStateChanged = TRUE; } if( bSlotStateChanged || m_bReinsertTheCard ) { m_bReinsertTheCard = FALSE; // If a card is inserted, unload the driver... if(m_bDevicePresent == TRUE) { m_fCardInTheSlot = FALSE; // indicate the slot change SDHCDIndicateSlotStateChange(m_pHCContext, 0, DeviceEjected); m_bDevicePresent = FALSE; Stop_SDI_Clock(); } if(IsCardPresent()) { m_fCardInTheSlot = TRUE; m_bDevicePresent = TRUE; //----- 5. Reset the clock to the ID rate ----- vm_pSDIReg->SDICON |= LITTLE_ENDIAN_BYTE_ORDER; // Windows CE is always Little Endian. vm_pSDIReg->SDICON |= RESET_FIFO; // Reset the FIFO vm_pSDIReg->SDIBSIZE = BYTES_PER_SECTOR; vm_pSDIReg->SDIDTIMER = MAX_DATABUSY_TIMEOUT; // Data/busy timeout SetClockRate(SD_DEFAULT_CARD_ID_CLOCK_RATE); // give the card enough time for initialization Start_SDI_Clock(); Wait_80_SDI_Clock_Cycles(); //----- 6. Inform the bus handler that this is the first command sent ----- m_bSendInitClocks = TRUE; //----- 7. Indicate the slot change ----- SDHCDIndicateSlotStateChange(m_pHCContext, 0, DeviceInserted); } } // if } // for return TRUE; }
12.SendCommand
在BusRequestHandler中被调用,首先清除SDICSTA状态标志位,设置SDICARG命令参数寄存器.判断命令是否带数据设置SDICCON.根据不同的Response类型SDICCON进行不同设置.NoResponse时,写命令到SDICCON并发送命令,并确定发送完成.Short response时,SDICCON设置WAIT_FOR_RESPONSE.ResponseR2时,SDICCON设置LONG_RESPONSE | WAIT_FOR_RESPONSE.
SD_API_STATUS CSDIOControllerBase::SendCommand(UINT16 Cmd, UINT32 Arg, UINT16 respType, BOOL bDataTransfer) { unsigned int uiNewCmdRegVal = 0; DWORD dwWaitCount = 0; DEBUGMSG (SDHC_SEND_ZONE,(TEXT("SendCommand (0x%08x, 0x%04x, 0x%08x, 0x%04x, 0x%x) starts"), this, Cmd, Arg, respType, bDataTransfer)); //----- 1. Reset any pending status flags ----- vm_pSDIReg->SDICSTA = (CRC_CHECK_FAILED | COMMAND_SENT | COMMAND_TIMED_OUT | RESPONSE_RECEIVED); //----- 2. Specify the command's argument ----- vm_pSDIReg->SDICARG = Arg; //----- 3. Specify the command's data transfer requirements ----- if(bDataTransfer == TRUE) { vm_pSDIReg->SDICCON |= SDIO_COMMAND_WITH_DATA; }else { vm_pSDIReg->SDICCON &= ~SDIO_COMMAND_WITH_DATA; } //----- 4. Send the command to the MMC controller ----- switch(respType) { case NoResponse: // Response is not required, but make sure the command was sent DEBUGMSG (SDHC_RESPONSE_ZONE,(TEXT("SendCommand no response required"))); vm_pSDIReg->SDICCON = START_COMMAND | COMMAND_START_BIT | (Cmd & MAX_CMD_VALUE); while(!(vm_pSDIReg->SDICSTA & COMMAND_SENT)) { dwWaitCount++; if( dwWaitCount > WAIT_TIME ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SendCommand() - timeout waiting for command completion!/r/n"))); return SD_API_STATUS_RESPONSE_TIMEOUT; } if( !IsCardPresent() ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SendCommand() - Card ejected!/r/n"))); return SD_API_STATUS_DEVICE_REMOVED; } if(vm_pSDIReg->SDICSTA & COMMAND_TIMED_OUT) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SendCommand() - Command 0x%04x timed out!/r/n"), Cmd)); vm_pSDIReg->SDICSTA = COMMAND_TIMED_OUT; // Clear the error return SD_API_STATUS_RESPONSE_TIMEOUT; } } vm_pSDIReg->SDICSTA = COMMAND_SENT; // Clear the status break; case ResponseR1: // Short response required case ResponseR1b: case ResponseR3: case ResponseR4: case ResponseR5: case ResponseR6: DEBUGMSG (SDHC_RESPONSE_ZONE,(TEXT("sendSDICommand short response required"))); // vm_pSDIReg->SDICCON = uiNewCmdRegVal | WAIT_FOR_RESPONSE | START_COMMAND | COMMAND_START_BIT | (Cmd & MAX_CMD_VALUE); vm_pSDIReg->SDICCON = WAIT_FOR_RESPONSE | START_COMMAND | COMMAND_START_BIT | (Cmd & MAX_CMD_VALUE); break; case ResponseR2: // Long response required DEBUGMSG (SDHC_RESPONSE_ZONE,(TEXT("sendSDICommand long response required"))); // vm_pSDIReg->SDICCON = uiNewCmdRegVal | LONG_RESPONSE | WAIT_FOR_RESPONSE | START_COMMAND | COMMAND_START_BIT | (Cmd & MAX_CMD_VALUE); vm_pSDIReg->SDICCON = LONG_RESPONSE | WAIT_FOR_RESPONSE | START_COMMAND | COMMAND_START_BIT | (Cmd & MAX_CMD_VALUE); break; default: DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:sendSDICommand() - Invalid response type. Command not sent!/r/n"))); return SD_API_STATUS_NOT_IMPLEMENTED; break; } return SD_API_STATUS_SUCCESS; }
13.GetCommandResponse
该函数用来获取命令应答,在TransferIstThread被调用.读取SDICSTA直到命令应答接收,如果有错误状态就返回错误.然后根据不同的应答类型分别读取SDIRSP0,SDIRSP1,SDIRSP2,SDIRSP3,具体格式参加代码注释.
SD_API_STATUS CSDIOControllerBase::GetCommandResponse(PSD_BUS_REQUEST pRequest) { DEBUGMSG (SDHC_RESPONSE_ZONE,(TEXT("GetCommandResponse started"))); PUCHAR respBuff; // response buffer DWORD dwWaitCount = 0; //----- 1. Wait for the response information to get arrive at the controller ----- while(!(vm_pSDIReg->SDICSTA & RESPONSE_RECEIVED)) { dwWaitCount++; if( dwWaitCount > WAIT_TIME ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:GetCommandResponse() - timeout waiting for command response!/r/n"))); return SD_API_STATUS_RESPONSE_TIMEOUT; } if( !IsCardPresent() ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:GetCommandResponse() - Card ejected!/r/n"))); return SD_API_STATUS_DEVICE_REMOVED; } if(vm_pSDIReg->SDICSTA & COMMAND_TIMED_OUT) { vm_pSDIReg->SDICSTA = COMMAND_TIMED_OUT; // Clear the error DEBUGMSG (SDCARD_ZONE_ERROR,(TEXT("GetCommandResponse returned SD_API_STATUS_RESPONSE_TIMEOUT (COMMAND_TIMED_OUT)"))); return SD_API_STATUS_RESPONSE_TIMEOUT; } if(vm_pSDIReg->SDIDSTA & CRC_CHECK_FAILED) { vm_pSDIReg->SDIDSTA = CRC_CHECK_FAILED; // Clear the error DEBUGMSG (SDCARD_ZONE_ERROR,(TEXT("GetCommandResponse returned SD_API_STATUS_CRC_ERROR (CRC_CHECK_FAILED)"))); return SD_API_STATUS_CRC_ERROR; } if(vm_pSDIReg->SDIDSTA & DATA_TRANSMIT_CRC_ERROR) { vm_pSDIReg->SDIDSTA = DATA_TRANSMIT_CRC_ERROR; // Clear the error DEBUGMSG (SDCARD_ZONE_ERROR,(TEXT("getSDICommandResponse returned SD_API_STATUS_CRC_ERROR (DATA_TRANSMIT_CRC_ERROR)"))); return SD_API_STATUS_CRC_ERROR; } if(vm_pSDIReg->SDIDSTA & DATA_RECEIVE_CRC_ERROR) { vm_pSDIReg->SDIDSTA = DATA_RECEIVE_CRC_ERROR; // Clear the error DEBUGMSG (SDCARD_ZONE_ERROR,(TEXT("GetCommandResponse returned SD_API_STATUS_CRC_ERROR (DATA_RECEIVE_CRC_ERROR)"))); return SD_API_STATUS_CRC_ERROR; } if(vm_pSDIReg->SDIDSTA & DATA_TIME_OUT) { vm_pSDIReg->SDIDSTA = DATA_TIME_OUT; // Clear the error DEBUGMSG (SDCARD_ZONE_ERROR,(TEXT("GetCommandResponse returned SD_API_STATUS_DATA_TIMEOUT (DATA_TIME_OUT)"))); return SD_API_STATUS_DATA_TIMEOUT; } } vm_pSDIReg->SDICSTA = RESPONSE_RECEIVED; // Clear the status //----- 2. Copy the response information to our "response buffer" ----- // NOTE: All START_BIT and TRANSMISSION_BIT bits ='0'. All END_BIT bits ='0'. All RESERVED bits ='1' respBuff = pRequest->CommandResponse.ResponseBuffer; switch(pRequest->CommandResponse.ResponseType) { case NoResponse: break; case ResponseR1: case ResponseR1b: //--- SHORT RESPONSE (48 bits total)--- // Format: { START_BIT(1) | TRANSMISSION_BIT(1) | COMMAND_INDEX(6) | CARD_STATUS(32) | CRC7(7) | END_BIT(1) } // NOTE: START_BIT and TRANSMISSION_BIT = 0, END_BIT = 1 // *(respBuff ) = (BYTE)(START_BIT | TRANSMISSION_BIT | pRequest->CommandCode); *(respBuff + 1) = (BYTE)(vm_pSDIReg->SDIRSP0 ); *(respBuff + 2) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 8 ); *(respBuff + 3) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 16); *(respBuff + 4) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 24); *(respBuff + 5) = (BYTE)(END_RESERVED | END_BIT); break; case ResponseR3: case ResponseR4: //--- SHORT RESPONSE (48 bits total)--- // Format: { START_BIT(1) | TRANSMISSION_BIT(1) | RESERVED(6) | CARD_STATUS(32) | RESERVED(7) | END_BIT(1) } // *(respBuff ) = (BYTE)(START_BIT | TRANSMISSION_BIT | START_RESERVED); *(respBuff + 1) = (BYTE)(vm_pSDIReg->SDIRSP0 ); *(respBuff + 2) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 8 ); *(respBuff + 3) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 16); *(respBuff + 4) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 24); *(respBuff + 5) = (BYTE)(END_RESERVED | END_BIT); break; case ResponseR5: case ResponseR6: //--- SHORT RESPONSE (48 bits total)--- // Format: { START_BIT(1) | TRANSMISSION_BIT(1) | COMMAND_INDEX(6) | RCA(16) | CARD_STATUS(16) | CRC7(7) | END_BIT(1) } // *(respBuff ) = (BYTE)(START_BIT | TRANSMISSION_BIT | pRequest->CommandCode); *(respBuff + 1) = (BYTE)(vm_pSDIReg->SDIRSP0 ); *(respBuff + 2) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 8 ); *(respBuff + 3) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 16); *(respBuff + 4) = (BYTE)(vm_pSDIReg->SDIRSP0 >> 24); *(respBuff + 5) = (BYTE)(vm_pSDIReg->SDIRSP1 >> 24); break; case ResponseR2: //--- LONG RESPONSE (136 bits total)--- // Format: { START_BIT(1) | TRANSMISSION_BIT(1) | RESERVED(6) | CARD_STATUS(127) | END_BIT(1) } // // NOTE: In this implementation, the caller doesn't require the upper 8 bits of reserved data. // Consequently, these bits aren't included and the response info is copied directly into // the beginning of the supplied buffer. // //*(respBuff ) = (BYTE)(START_BIT | TRANSMISSION_BIT | START_RESERVED); // *(respBuff + 0) = (BYTE)(vm_pSDIReg->SDIRSP3 ); *(respBuff + 1) = (BYTE)(vm_pSDIReg->SDIRSP3 >> 8 ); *(respBuff + 2) = (BYTE)(vm_pSDIReg->SDIRSP3 >> 16); *(respBuff + 3) = (BYTE)(vm_pSDIReg->SDIRSP3 >> 24); *(respBuff + 4) = (BYTE)(vm_pSDIReg->SDIRSP2 ); *(respBuff + 5) = (BYTE)(vm_pSDIReg->SDIRSP2 >> 8 ); *(respBuff + 6) = (BYTE)(vm_pSDIReg->SDIRSP2 >> 16); *(respBuff + 7) = (BYTE)(vm_pSDIReg->SDIRSP2 >> 24); *(respBuff + 8) = (BYTE)(vm_pSDIReg->SDIRSP1 ); *(respBuff + 9) = (BYTE)(vm_pSDIReg->SDIRSP1 >> 8 ); *(respBuff + 10)= (BYTE)(vm_pSDIReg->SDIRSP1 >> 16); *(respBuff + 11)= (BYTE)(vm_pSDIReg->SDIRSP1 >> 24); *(respBuff + 12)= (BYTE)(vm_pSDIReg->SDIRSP0 ); *(respBuff + 13)= (BYTE)(vm_pSDIReg->SDIRSP0 >> 8 ); *(respBuff + 14)= (BYTE)(vm_pSDIReg->SDIRSP0 >> 16); *(respBuff + 15)= (BYTE)(vm_pSDIReg->SDIRSP0 >> 24); break; default: DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:GetCmdResponse(): Unrecognized response type!/r/n"))); break; } DEBUGMSG (SDHC_RESPONSE_ZONE,(TEXT("GetCommandResponse returned SD_API_STATUS_SUCCESS"))); return SD_API_STATUS_SUCCESS; }
14.SetupDmaXfer
DMA传输,分两种情况SD_READ和SD_WRITE,首先设置request类型(SD_READ或SD_WRITE),reset fifo,设置BlockSize(SDIBSIZE寄存器),根据m_dwDMAChannel(0-3)设置DMA寄存器,设置源/目的地址,源地址periperal bus, fixed addr,目的地址system bus, increment addr,设置DMA通道传输特性handshake, sync PCLK, interrupt, single RX, single service,, MMC request, no auto-reload, word (32 bits), RX count,SD_READ和SD_WRITE的源和目的地址正好相反.
当SD_CMD_STOP_TRANSMISSION命令时,设置BUSY_AFTER_COMMAND
BOOL CSDIOControllerBase::SetupDmaXfer(PSD_BUS_REQUEST pRequest) { //----- 1. Check the parameters ----- if(!pRequest) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SetupDmaXfer() - Invalid parameters!/r/n"))); return FALSE; } //----- 2. Setup the SD/MMC controller according to the type of transfer ----- switch(pRequest->TransferClass) { case SD_READ: //********* 3. READ request ********* m_dwLastTypeOfTransfer = SD_READ; //----- 3a. Reset the FIFO ----- vm_pSDIReg->SDIDTIMER = MAX_DATABUSY_TIMEOUT; vm_pSDIReg->SDIBSIZE = pRequest->BlockSize; Stop_SDIO_DMA_Channel(); switch( m_dwDMAChannel ) { case 0: //----- 3b. Initialize the DMA channel for input mode ----- vm_pDMAreg->DISRC0 = (int)MMCFIF_PHYS; vm_pDMAreg->DISRCC0 |= (SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr vm_pDMAreg->DIDST0 = (int)m_pDMABufferPhys.LowPart; vm_pDMAreg->DIDSTC0 &= ~(DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr //----- 3c. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, ----- // single RX, single service,, MMC request, no auto-reload, word (32 bits), RX count vm_pDMAreg->DCON0 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | MMC_DMA0 | DMA_TRIGGERED_BY_HARDWARE | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | ((pRequest->BlockSize / sizeof(DWORD)) * pRequest->NumBlocks)); break; case 1: //----- 3b. Initialize the DMA channel for input mode ----- vm_pDMAreg->DISRC1 = (int)MMCFIF_PHYS; vm_pDMAreg->DISRCC1 |= (SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr vm_pDMAreg->DIDST1 = (int)m_pDMABufferPhys.LowPart; vm_pDMAreg->DIDSTC1 &= ~(DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr //----- 3c. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, ----- // single RX, single service,, MMC request, no auto-reload, word (32 bits), RX count vm_pDMAreg->DCON1 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | MMC_DMA0 | DMA_TRIGGERED_BY_HARDWARE | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | ((pRequest->BlockSize / sizeof(DWORD)) * pRequest->NumBlocks)); break; case 2: //----- 3b. Initialize the DMA channel for input mode ----- vm_pDMAreg->DISRC2 = (int)MMCFIF_PHYS; vm_pDMAreg->DISRCC2 |= (SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr vm_pDMAreg->DIDST2 = (int)m_pDMABufferPhys.LowPart; vm_pDMAreg->DIDSTC2 &= ~(DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr //----- 3c. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, ----- // single RX, single service,, MMC request, no auto-reload, word (32 bits), RX count vm_pDMAreg->DCON2 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | MMC_DMA0 | DMA_TRIGGERED_BY_HARDWARE | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | ((pRequest->BlockSize / sizeof(DWORD)) * pRequest->NumBlocks)); break; case 3: //----- 3b. Initialize the DMA channel for input mode ----- vm_pDMAreg->DISRC3 = (int)MMCFIF_PHYS; vm_pDMAreg->DISRCC3 |= (SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr vm_pDMAreg->DIDST3 = (int)m_pDMABufferPhys.LowPart; vm_pDMAreg->DIDSTC3 &= ~(DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr //----- 3c. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, ----- // single RX, single service,, MMC request, no auto-reload, word (32 bits), RX count vm_pDMAreg->DCON3 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | MMC_DMA0 | DMA_TRIGGERED_BY_HARDWARE | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | ((pRequest->BlockSize / sizeof(DWORD)) * pRequest->NumBlocks)); break; default: ASSERT(0); // invalid DMA Channel... we should never get here } //----- 3d. Setup the controller and DMA channel appropriately ----- vm_pSDIReg->SDIDCON = RECEIVE_AFTER_COMMAND | TRANSFER_BLOCK_MODE | Get_SDI_Bus_Width() | DMA_ENABLE | DATA_RECEIVE_START | pRequest->NumBlocks; break; case SD_WRITE: //********* 4. WRITE request ********* m_dwLastTypeOfTransfer = SD_WRITE; //----- 4a. Reset the FIFO ----- vm_pSDIReg->SDIDTIMER = MAX_DATABUSY_TIMEOUT; vm_pSDIReg->SDIBSIZE = pRequest->BlockSize; Stop_SDIO_DMA_Channel(); switch( m_dwDMAChannel ) { case 0: //----- 4b. Initialize the DMA channel for output mode ----- vm_pDMAreg->DISRC0 = (int)m_pDMABufferPhys.LowPart; vm_pDMAreg->DISRCC0 &= ~(SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr vm_pDMAreg->DIDST0 = (int)MMCFIF_PHYS; vm_pDMAreg->DIDSTC0 |= (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr //----- 4c. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, ----- // single TX, single service, MMC request, no auto-reload, word (32 bits), TX count vm_pDMAreg->DCON0 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | MMC_DMA0 | DMA_TRIGGERED_BY_HARDWARE | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | ((pRequest->BlockSize / sizeof(DWORD)) * pRequest->NumBlocks)); break; case 1: //----- 4b. Initialize the DMA channel for output mode ----- vm_pDMAreg->DISRC1 = (int)m_pDMABufferPhys.LowPart; vm_pDMAreg->DISRCC1 &= ~(SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr vm_pDMAreg->DIDST1 = (int)MMCFIF_PHYS; vm_pDMAreg->DIDSTC1 |= (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr //----- 4c. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, ----- // single TX, single service, MMC request, no auto-reload, word (32 bits), TX count vm_pDMAreg->DCON1 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | MMC_DMA0 | DMA_TRIGGERED_BY_HARDWARE | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | ((pRequest->BlockSize / sizeof(DWORD)) * pRequest->NumBlocks)); break; case 2: //----- 4b. Initialize the DMA channel for output mode ----- vm_pDMAreg->DISRC2 = (int)m_pDMABufferPhys.LowPart; vm_pDMAreg->DISRCC2 &= ~(SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr vm_pDMAreg->DIDST2 = (int)MMCFIF_PHYS; vm_pDMAreg->DIDSTC2 |= (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr //----- 4c. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, ----- // single TX, single service, MMC request, no auto-reload, word (32 bits), TX count vm_pDMAreg->DCON2 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | MMC_DMA0 | DMA_TRIGGERED_BY_HARDWARE | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | ((pRequest->BlockSize / sizeof(DWORD)) * pRequest->NumBlocks)); break; case 3: //----- 4b. Initialize the DMA channel for output mode ----- vm_pDMAreg->DISRC3 = (int)m_pDMABufferPhys.LowPart; vm_pDMAreg->DISRCC3 &= ~(SOURCE_PERIPHERAL_BUS | FIXED_SOURCE_ADDRESS); // Source is periperal bus, fixed addr vm_pDMAreg->DIDST3 = (int)MMCFIF_PHYS; vm_pDMAreg->DIDSTC3 |= (DESTINATION_PERIPHERAL_BUS | FIXED_DESTINATION_ADDRESS); // Destination is system bus, increment addr //----- 4c. Configure the DMA channel's transfer characteristics: handshake, sync PCLK, interrupt, ----- // single TX, single service, MMC request, no auto-reload, word (32 bits), TX count vm_pDMAreg->DCON3 = ( HANDSHAKE_MODE | GENERATE_INTERRUPT | MMC_DMA0 | DMA_TRIGGERED_BY_HARDWARE | NO_DMA_AUTO_RELOAD | TRANSFER_WORD | ((pRequest->BlockSize / sizeof(DWORD)) * pRequest->NumBlocks)); break; default: ASSERT(0); // invalid DMA Channel... we should never get here } //----- 4d. Setup the controller and DMA channel appropriately ----- vm_pSDIReg->SDIDCON = TRANSMIT_AFTER_RESPONSE | TRANSFER_BLOCK_MODE | Get_SDI_Bus_Width() | DMA_ENABLE | DATA_TRANSMIT_START | pRequest->NumBlocks; break; case SD_COMMAND: //----- 5. SPECIAL CASE: The SD_CMD_STOP_TRANSMISSION command requires that BUSY_AFTER_COMMAND be setup. ----- if( ( m_fHandleBusyCheckOnCommand38 && pRequest->CommandCode == SD_CMD_ERASE ) || ( ( pRequest->CommandCode == SD_CMD_STOP_TRANSMISSION ) && ( m_dwLastTypeOfTransfer == SD_WRITE ) ) ) { vm_pSDIReg->SDIDCON = BUSY_AFTER_COMMAND | TRANSFER_BLOCK_MODE | DATA_BUSY | pRequest->NumBlocks; } break; default: DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SetupDmaXfer(): Unrecognized transfer mode!/r/n"))); return FALSE; } return TRUE; }
15.IsCardBusy
检查Card是否处在Busy状态.检查SDICSTA和SDIDSTA状态寄存器,COMMAND_IN_PROGRESS,DATA_TRANSMIT_IN_PROGRESS,DATA_RECIEVE_IN_PROGRESS,READ_WAIT_REQUEST_OCCURE状态发生时,Card处于Busy状态.
BOOL CSDIOControllerBase::IsCardBusy(UINT16 inData) { //----- 1. Is there a command currently in progress? ----- if(vm_pSDIReg->SDICSTA & COMMAND_IN_PROGRESS) return TRUE; //----- 2. Is there a transfer in progress? ----- if((vm_pSDIReg->SDIDSTA & DATA_TRANSMIT_IN_PROGRESS) || (vm_pSDIReg->SDIDSTA & DATA_RECIEVE_IN_PROGRESS)) return TRUE; //----- 3. Is there a READ-WAIT request in progress? ----- if(vm_pSDIReg->SDIDSTA & READ_WAIT_REQUEST_OCCURED) return TRUE; return FALSE; }
16.SetClockRate
设置SDI clock时钟频率.首先检查参数正确性,频率最大为25MHz.如果输入MMC全速频率20MHz,由于2410在20MHz会有问题,所以设置成20MHz,然后计算分频值prescale = ((PCLK / (2*baud_rate)) - 1,然后确保SDI时钟处于停止状态,最后设置SDIPRE寄存器设置分配值,并启动SDI时钟.
DWORD CSDIOControllerBase::SetClockRate(DWORD dwClockRate) { if((dwClockRate < 0) || (dwClockRate > SD_FULL_SPEED_RATE)) { DEBUGMSG(ZONE_ENABLE_ERROR, (TEXT("SDHCDriver:SetClockRate() - invalid clock rate %d !/r/n"), dwClockRate)); goto DONE; } //----- BUGBUG ----- // HARDWARE BUG WORKAROUND // // The newest datasheet for the S3C2410X states that the maximum reliable speed for MMC cards is 10Mhz. // Some limited testing has shown 20Mhz to still be reliable, but for extra caution let's use 10Mhz. if(dwClockRate == MMC_FULL_SPEED_RATE) { dwClockRate = 10000000; } //----- 2. Calculate the clock rate ----- // NOTE: Using the prescale value, the clock's baud rate is // determined as follows: baud_rate = (PCLK / 2 / (prescale + 1)) // // Hence, the prescale value can be computed as follows: // prescale = ((PCLK / (2*baud_rate)) - 1 DWORD dwPrescale = dwClockRate ? ( (PCLK / (2*dwClockRate)) - 1 ) : 0xff; DWORD dwActualRate = PCLK / 2 / ( dwPrescale + 1 ); // adjust the rate if too high if( dwActualRate > dwClockRate ) { dwPrescale++; // set to next supported lower rate // recalculate the actual rate dwActualRate = PCLK / 2 / ( dwPrescale + 1 ); } // adjust the rate if too low if( dwPrescale > 0xff ) { dwPrescale = 0xff; // set to slowest supported rate // recalculate the actual rate dwActualRate = PCLK / 2 / ( dwPrescale + 1 ); } BOOL fClockIsRunning = Is_SDI_Clock_Running(); //----- 2. Make sure the clock is stopped ----- if( fClockIsRunning ) { Stop_SDI_Clock(); } //----- 3. Set the clock rate ----- vm_pSDIReg->SDIPRE = dwPrescale; DEBUGMSG(SDHC_CLOCK_ZONE, (TEXT("SDHCD:SetClockRate() - Clock rate set to %d Hz/n"), dwActualRate)); if( fClockIsRunning ) { Start_SDI_Clock(); } // remember the current clock rate m_dwClockRate = dwActualRate; DONE: return m_dwClockRate; }
17.PollingTransmit
用来轮询发送数据.首先判断一些错误状态是否发生,如卡不再插槽,FIFO Fail,CRC error等就返回false.状态正常则读取SDIFSTA看FIFO能否接收更多数据.可以就向SDIDAT写数据.直至FIFO满为止.然后监测数据是否写完,并设置DATA_TRANSMIT_FINISHED.
BOOL CSDIOControllerBase::PollingTransmit(PSD_BUS_REQUEST pRequest, DWORD dwLen) { BOOL fRetVal = TRUE; PBYTE pBuff = pRequest->pBlockBuffer; SD_SET_PROC_PERMISSIONS_FROM_REQUEST( pRequest ) { __try { //----- 1. Send the data to the FIFO ----- while(dwLen > 0) { if( !m_fCardInTheSlot ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - Card ejected!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & FIFO_FAIL_ERROR)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - FIFO Error!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & DATA_TRANSMIT_CRC_ERROR)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - Transmit CRC Error!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & DATA_TIME_OUT)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - Data timeout!/r/n"))); fRetVal = FALSE; break; } //----- 2. Is the FIFO ready to accept more data? ----- if((vm_pSDIReg->SDIFSTA & FIFO_AVAIL_FOR_TX)) { *(PBYTE)&(vm_pSDIReg->SDIDAT) = *pBuff++; dwLen--; } } } __except (SDProcessException(GetExceptionInformation())) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("--- SDHC Driver: Exception caught in PollingTransmit/n"))); fRetVal = FALSE; } } SD_RESTORE_PROC_PERMISSIONS(); if( fRetVal ) { DWORD dwWaitCount = 0; //----- 4. Make sure the transmit completes! ----- while(!(vm_pSDIReg->SDIDSTA & DATA_TRANSMIT_FINISHED)) { dwWaitCount++; if( dwWaitCount > WAIT_TIME ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - timeout waiting for DATA_TRANSMIT_FINISHED!/r/n"))); return SD_API_STATUS_RESPONSE_TIMEOUT; } if( !IsCardPresent() ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - Card ejected!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & FIFO_FAIL_ERROR)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - FIFO Error waiting for DATA_TRANSMIT_FINISHED!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & DATA_TRANSMIT_CRC_ERROR)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - Transmit CRC Error waiting for DATA_TRANSMIT_FINISHED!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & DATA_TIME_OUT)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:PollingTransmit() - Data timeout waiting for DATA_TRANSMIT_FINISHED!/r/n"))); fRetVal = FALSE; break; } } vm_pSDIReg->SDIDSTA = DATA_TRANSMIT_FINISHED; } return fRetVal; }
18.PollingReceive
轮询接收数据.首先判断一些错误状态是否发生,没有的话读SDIFSTA寄存器看是否有数据,有的话读取数据到缓冲区中.
BOOL CSDIOControllerBase::PollingReceive(PSD_BUS_REQUEST pRequest, DWORD dwLen) { BOOL fRetVal = TRUE; DEBUGCHK(m_dwNumBytesToTransfer <= MAXIMUM_DMA_TRANSFER_SIZE); PBYTE pBuff = pRequest->pBlockBuffer; SD_SET_PROC_PERMISSIONS_FROM_REQUEST( pRequest ) { __try { //----- 1. Read the data from the FIFO ----- while(dwLen > 0) { if( !m_fCardInTheSlot ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDIPollingReceive() - Card ejected!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & DATA_TIME_OUT)) { DEBUGMSG(ZONE_ENABLE_ERROR, (TEXT("SDHCD:SDIPollingReceive() - Data receive time out!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & FIFO_FAIL_ERROR)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDIPollingReceive() - FIFO Error!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & DATA_RECEIVE_CRC_ERROR)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDIPollingReceive() - Receive CRC Error!/r/n"))); fRetVal = FALSE; break; } if((vm_pSDIReg->SDIDSTA & DATA_TIME_OUT)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SDIPollingReceive() - Data timeout!/r/n"))); fRetVal = FALSE; break; } //----- 2. Does the FIFO have more data ready? ----- if((vm_pSDIReg->SDIFSTA & FIFO_AVAIL_FOR_RX)) { *pBuff++ = *(PBYTE)&(vm_pSDIReg->SDIDAT); dwLen--; } } } __except (SDProcessException(GetExceptionInformation())) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("--- SDHC Driver: Exception caught in PollingTransmit/n"))); fRetVal = FALSE; } } SD_RESTORE_PROC_PERMISSIONS(); return fRetVal; }
19.SetupPollingXfer
设置IO端口来初始化轮询.检查参数,Reset FIFO,然后根据传输类型(SD_READ,SD_WRITE,SD_COMMAND)来设置SDIBSIZE和SDIDCON寄存器.
BOOL CSDIOControllerBase::SetupPollingXfer(PSD_BUS_REQUEST pRequest) { //----- 1. Check the parameters ----- if(!pRequest) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SetupSDIXfer() - Invalid parameters!/r/n"))); return FALSE; } //----- 2. Reset the FIFO ----- vm_pSDIReg->SDICON |= RESET_FIFO; vm_pSDIReg->SDIDSTA |= FIFO_FAIL_ERROR; //----- 3. Setup the SDI controller according to the type of transfer ----- switch(pRequest->TransferClass) { case SD_READ: vm_pSDIReg->SDIBSIZE = pRequest->BlockSize; vm_pSDIReg->SDIDCON = RECEIVE_AFTER_COMMAND | TRANSFER_BLOCK_MODE | Get_SDI_Bus_Width() | DATA_RECEIVE_START | pRequest->NumBlocks; break; case SD_WRITE: vm_pSDIReg->SDIBSIZE = pRequest->BlockSize; vm_pSDIReg->SDIDCON = TRANSMIT_AFTER_RESPONSE | TRANSFER_BLOCK_MODE | Get_SDI_Bus_Width() | DATA_TRANSMIT_START | pRequest->NumBlocks; break; case SD_COMMAND: //----- 4. SPECIAL CASE: The SD_CMD_STOP_TRANSMISSION command requires that BUSY_AFTER_COMMAND be setup. ----- if((pRequest->CommandCode == SD_CMD_STOP_TRANSMISSION) && (m_dwLastTypeOfTransfer == SD_WRITE)) { vm_pSDIReg->SDIBSIZE = pRequest->BlockSize; vm_pSDIReg->SDIDCON = BUSY_AFTER_COMMAND | TRANSFER_BLOCK_MODE | DATA_BUSY | pRequest->NumBlocks; } break; default: DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD:SetupPollingXfer(): Unrecognized transfer mode!/r/n"))); return FALSE; } return TRUE; }
20.SD_CardDetectThread,SD_IOInterruptIstThread,SD_TransferIstThread
分别对应于CardDetectThread,SD_IOInterruptIstThread,SD_TransferIstThread
DWORD CSDIOControllerBase::SD_CardDetectThread(CSDIOControllerBase *pController) { return pController->CardDetectThread(); } DWORD CSDIOControllerBase::SD_IOInterruptIstThread(CSDIOControllerBase *pController) { return pController->IOInterruptIstThread(); } DWORD CSDIOControllerBase::SD_TransferIstThread(CSDIOControllerBase *pController) { return pController->TransferIstThread(); }
21.SDHCDInitialize,SDHCDDeinitialize,SDHCDCancelIoHandler,SDHCDBusRequestHandler,SDHCDSlotOptionHandler分别对应于Initialize,Deinitialize,CancelIoHandler,BusRequestHandler,SlotOptionHandler,这几个SDHCD handler在InterpretCapabilities被SDHCDSetControllerInitHandler,SDHCDSetControllerDeinitHandler,,SDHCDSetCancelIOHandler,SDHCDSetBusRequestHandler,SDHCDSetSlotOonHandler注册.实际上就是将这几个函数指针赋值给pHCContext对应的函数指针成员.
SD_API_STATUS CSDIOControllerBase::SDHCDInitialize(PSDCARD_HC_CONTEXT pHCContext) { // get our extension CSDIOControllerBase *pController = GET_PCONTROLLER_FROM_HCD(pHCContext); return pController->Initialize(); } SD_API_STATUS CSDIOControllerBase::SDHCDDeinitialize(PSDCARD_HC_CONTEXT pHCContext) { // get our extension CSDIOControllerBase *pController = GET_PCONTROLLER_FROM_HCD(pHCContext); return pController->Deinitialize(); } BOOLEAN CSDIOControllerBase::SDHCDCancelIoHandler(PSDCARD_HC_CONTEXT pHCContext, DWORD dwSlot, PSD_BUS_REQUEST pRequest) { // get our extension CSDIOControllerBase *pController = GET_PCONTROLLER_FROM_HCD(pHCContext); return pController->CancelIoHandler(dwSlot, pRequest); } SD_API_STATUS CSDIOControllerBase::SDHCDBusRequestHandler(PSDCARD_HC_CONTEXT pHCContext, DWORD dwSlot, PSD_BUS_REQUEST pRequest) { // get our extension CSDIOControllerBase *pController = GET_PCONTROLLER_FROM_HCD(pHCContext); return pController->BusRequestHandler(dwSlot, pRequest); } SD_API_STATUS CSDIOControllerBase::SDHCDSlotOptionHandler(PSDCARD_HC_CONTEXT pHCContext, DWORD dwSlot, SD_SLOT_OPTION_CODE Option, PVOID pData, ULONG OptionSize) { // get our extension CSDIOControllerBase *pController = GET_PCONTROLLER_FROM_HCD(pHCContext); return pController->SlotOptionHandler(dwSlot, Option, pData, OptionSize); }
22.InterpretCapabilities
在SDH_Init中调用,从注册表中读取配置信息.首先打开注册表,读取SD IRQ("SDIOIrq"=dword:15),然后向系统申请逻辑中断号.接着读取SDIO IST优先级("SDIO_IST_Priority"=dword:97),DMA通道号("DMAChannel"=dword:0).DMA IRQ("DMAIrq"=dword:11)并申请对应的逻辑中断号,接着读取DMA IST优先级,SD卡监测线程的轮询周期,HandleBusyFinishOnCommand39,DMA的一些信息等.调用CustomSetup(实现在sdiocontroller.cpp,CSDIOControllerBase的继承类CSDIOController)来进行和实际平台相关的初始化工作.
最后调用SDHCDSetHCName,SDHCDSetControllerInitHandler等进行m_pHCContext的成员赋值.
BOOL CSDIOControllerBase::InterpretCapabilities( LPCTSTR pszRegistryPath ) { BOOL fRetVal = TRUE; CReg regDevice; // encapsulated device key HKEY hKeyDevice = OpenDeviceKey(pszRegistryPath); if ( (hKeyDevice == NULL) || !regDevice.Open(hKeyDevice, NULL) ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("CSDIOControllerBase::InterpretCapabilities: Failed to open device key/n"))); fRetVal = FALSE; goto FUNCTION_EXIT; } // read registry settings // read the SDIO SYSINTR value m_dwSDIOIrq = regDevice.ValueDW( SDIO_IRQ_TEXT, 0xffffffff ); if( m_dwSDIOIrq == 0xffffffff ) { // invalid SDIO IRQ value! DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("invalid SDIO IRQ value!/n"))); fRetVal = FALSE; goto FUNCTION_EXIT; } // convert the SDI hardware IRQ into a logical SYSINTR value if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &m_dwSDIOIrq, sizeof(DWORD), &m_dwSDIOSysIntr, sizeof(DWORD), NULL)) { // invalid SDIO SYSINTR value! DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("invalid SDIO SYSINTR value!/n"))); m_dwSDIOSysIntr = SYSINTR_UNDEFINED; fRetVal = FALSE; goto FUNCTION_EXIT; } // read the SDIO IST priority m_nSDIOIstThreadPriority = regDevice.ValueDW( SDIO_IST_PRIORITY_TEXT, 0xffffffff ); // read the DMA channel number m_dwDMAChannel = regDevice.ValueDW( DMA_CHANNEL_TEXT, 0xffffffff ); // read the DMA IRQ value m_dwDMAIrq = regDevice.ValueDW( DMA_IRQ_TEXT, 0xffffffff ); if( m_dwDMAIrq == 0xffffffff ) { // invalid DMA IRQ value! m_dwDMAChannel = 0xffffffff; // disable DMA } // convert the DMA hardware IRQ into a logical SYSINTR value. if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &m_dwDMAIrq, sizeof(DWORD), &m_dwDMASysIntr, sizeof(DWORD), NULL)) { // invalid DMA IRQ value! m_dwDMAChannel = 0xffffffff; // disable DMA } // read the DMA IST priority m_DMAIstThreadPriority = regDevice.ValueDW( DMA_IST_PRIORITY_TEXT, 0xffffffff ); // read the card detect thread polling timeout (default 100 ms) m_dwPollingTimeout = regDevice.ValueDW( POLLING_TIMEOUT_TEXT, 150 ); // read the card detect thread priority m_nCardDetectIstThreadPriority = regDevice.ValueDW( CARD_DETECT_THREAD_PRIORITY_TEXT, 0xffffffff ); // read the HandleBusyFinishOnCommand38 m_fHandleBusyCheckOnCommand38 = regDevice.ValueDW( HANDLE_BUSY_FINISH_ON_COMMAND38_TEXT, 0 ) ? TRUE : FALSE; // read the DMA transfer timeout factor m_dwDMATransferTimeoutFactor = regDevice.ValueDW( DMA_TRANSFER_TIMEOUT_FACTOR_TEXT, 8 ); // read the DMA transfer timeout constant m_dwDMATransferTimeoutConstant = regDevice.ValueDW( DMA_TRANSFER_TIMEOUT_CONSTANT_TEXT, 3000 ); // call the custom (overrideable) routine for custom, hardware specific settings if( !CustomSetup( pszRegistryPath ) ) { fRetVal = FALSE; goto FUNCTION_EXIT; } /* // set the slot capabilities SDHCDSetSlotCapabilities(m_pHCContext, SD_SLOT_SD_1BIT_CAPABLE | SD_SLOT_SD_4BIT_CAPABLE | SD_SLOT_SDIO_CAPABLE | SD_SLOT_SDIO_INT_DETECT_4BIT_MULTI_BLOCK); // this platform has 3.3V tied directly to the slot SDHCDSetVoltageWindowMask(m_pHCContext, (SD_VDD_WINDOW_3_2_TO_3_3 | SD_VDD_WINDOW_3_3_TO_3_4)); // set on the low side SDHCDSetDesiredSlotVoltage(m_pHCContext, SD_VDD_WINDOW_3_2_TO_3_3); // the SD/MMC controller tops out at MAX_SDI_BUS_TRANSFER_SPEED SDHCDSetMaxClockRate(m_pHCContext, MAX_SDI_BUS_TRANSFER_SPEED); // power up settling time (estimated) SDHCDSetPowerUpDelay(m_pHCContext, 300); */ // set the name SDHCDSetHCName(m_pHCContext, TEXT("SDH")); // set init handler SDHCDSetControllerInitHandler(m_pHCContext, CSDIOControllerBase::SDHCDInitialize); // set deinit handler SDHCDSetControllerDeinitHandler(m_pHCContext, CSDIOControllerBase::SDHCDDeinitialize); // set the Send packet handler SDHCDSetBusRequestHandler(m_pHCContext, CSDIOControllerBase::SDHCDBusRequestHandler); // set the cancel I/O handler SDHCDSetCancelIOHandler(m_pHCContext, CSDIOControllerBase::SDHCDCancelIoHandler); // set the slot option handler SDHCDSetSlotOptionHandler(m_pHCContext, CSDIOControllerBase::SDHCDSlotOptionHandler); FUNCTION_EXIT: if (hKeyDevice) RegCloseKey(hKeyDevice); return fRetVal; }
23.GetHostContext
返回m_pHCContext
PSDCARD_HC_CONTEXT CSDIOControllerBase::GetHostContext() const { return m_pHCContext; }
24.MMC_Hardware_PowerUp,MMC_Hardware_PowerDown
启动禁止SDI时钟,设置CLKON寄存器bit9(Control PCLK into SDI interface block)
void CSDIOControllerBase::MMC_Hardware_PowerUp() { vm_pCLKPWR->CLKCON |= (1 << 9); } void CSDIOControllerBase::MMC_Hardware_PowerDown() { vm_pCLKPWR->CLKCON &= ~(1 << 9); }
25.Stop_SDI_Hardware
停止数据传输,设置SDIDCON bit14强制停止数据传输(Determine whether data transfer stop by force or not)
void CSDIOControllerBase::Stop_SDI_Hardware() { vm_pSDIReg->SDIDCON |= STOP_BY_FORCE; }
26.Set_SDI_Bus_Width_1Bit,Set_SDI_Bus_Width_4Bit,Get_SDI_Bus_Width
设置和获取bus位宽(1bit或4bit)
void CSDIOControllerBase::Set_SDI_Bus_Width_1Bit() { m_dwSDIBusWidth = 0; } void CSDIOControllerBase::Set_SDI_Bus_Width_4Bit() { m_dwSDIBusWidth = WIDE_BUS_ENABLE; } DWORD CSDIOControllerBase::Get_SDI_Bus_Width() { return m_dwSDIBusWidth; }
27.Wait_80_SDI_Clock_Cycles
延时,这里调用sleep(1)延时约1ms

void CSDIOControllerBase::Wait_80_SDI_Clock_Cycles() { // delay 80 clock cycles... we may need a better way to do this Sleep(1); // sleep 1 ms }
28.Start_SDI_Clock,Stop_SDI_Clock,Is_SDI_Clock_Running
设置SDICON bit0(Determine whether SDCLK Out enable or not)使能或禁止SDCLK输出.Is_SDI_Clock_Running用来获取clock状态.
void CSDIOControllerBase::Start_SDI_Clock() { vm_pSDIReg->SDICON |= CLOCK_ENABLE; DEBUGMSG(SDHC_CLOCK_ZONE, (TEXT("SDHCD: Clock started.../n"))); } void CSDIOControllerBase::Stop_SDI_Clock() { vm_pSDIReg->SDICON &= ~CLOCK_ENABLE; DEBUGMSG(SDHC_CLOCK_ZONE, (TEXT("SDHCD: Clock stopped.../n"))); } BOOL CSDIOControllerBase::Is_SDI_Clock_Running() { if( vm_pSDIReg->SDICON & CLOCK_ENABLE ) return TRUE; else return FALSE; }
29.Enable_SDIO_Interrupts,Disable_SDIO_Interrupts,Is_SDIO_Interrupt_Enabled,Is_SDIO_Interrupt_Enabled作用分别为使能/禁止SDIO中断,返回SDIO中断状态,清除中断标志.
void CSDIOControllerBase::Enable_SDIO_Interrupts() { vm_pSDIReg->SDICON |= SDIO_INTERRUPT_ENABLE; vm_pSDIReg->SDIIMSK |= SDIO_HOST_IO_INT; } void CSDIOControllerBase::Disable_SDIO_Interrupts() { vm_pSDIReg->SDICON &= ~SDIO_INTERRUPT_ENABLE; vm_pSDIReg->SDIIMSK &= ~SDIO_HOST_IO_INT; } BOOL CSDIOControllerBase::Is_SDIO_Interrupt_Enabled() { if( vm_pSDIReg->SDICON & SDIO_INTERRUPT_ENABLE ) return TRUE; else return FALSE; } void CSDIOControllerBase::Ack_SDIO_Interrupts() { vm_pSDIReg->SDIDSTA = SDIO_INTERRUPT_DETECTED; }
30.Enable_SDIO_DMA_Channel,Disable_SDIO_DMA_Channel
使能/禁止对应DMA通道(m_dwDMAChannel)
void CSDIOControllerBase::Enable_SDIO_Interrupts() { vm_pSDIReg->SDICON |= SDIO_INTERRUPT_ENABLE; vm_pSDIReg->SDIIMSK |= SDIO_HOST_IO_INT; } void CSDIOControllerBase::Disable_SDIO_Interrupts() { vm_pSDIReg->SDICON &= ~SDIO_INTERRUPT_ENABLE; vm_pSDIReg->SDIIMSK &= ~SDIO_HOST_IO_INT; } BOOL CSDIOControllerBase::Is_SDIO_Interrupt_Enabled() { if( vm_pSDIReg->SDICON & SDIO_INTERRUPT_ENABLE ) return TRUE; else return FALSE; } void CSDIOControllerBase::Ack_SDIO_Interrupts() { vm_pSDIReg->SDIDSTA = SDIO_INTERRUPT_DETECTED; }
31.OnPowerUp,OnPowerDown
这两个函数被流接口函数SDH_PowerUp和SDH_PowerDown调用.
OnPowerUp:
首先调用MMC_Hardware_PowerUp使能SDI时钟,配置GPIO进入SDI模式,设置SDI时钟默认频率(100KHz),配置SDI相关寄存器,如LITTLE_ENDIAN_BYTE_ORDER,RESET_FIFO,BYTES_PER_SECTOR(512)等,调用继承类的InitializeHardware函数进行硬件初始化(这个函数后面在介绍),启动SDI时钟,调用SDHCDPowerUpDown通知SD总线驱动PowerUp事件发生,设置事件m_hCardInsertInterruptEvent.
void CSDIOControllerBase::OnPowerUp() { // Supply the clock to the SDI controller MMC_Hardware_PowerUp(); // Reconfigure the GPIO lines for SDI mode and enable the pullup resistor ----- vm_pIOPreg->GPEUP &= 0xF83F; vm_pIOPreg->GPECON |= 0x2AA800; // Reset the SD/SDI controller to some reasonable default values ----- SetClockRate(SD_DEFAULT_CARD_ID_CLOCK_RATE); // 100Khz vm_pSDIReg->SDICON |= LITTLE_ENDIAN_BYTE_ORDER; // Windows CE is always Little Endian. vm_pSDIReg->SDICON |= RESET_FIFO; // Reset the FIFO vm_pSDIReg->SDIBSIZE = BYTES_PER_SECTOR; vm_pSDIReg->SDIDTIMER = MAX_DATABUSY_TIMEOUT; // Data/busy timeout // reinitialize the hardware InitializeHardware( TRUE ); // Start the SDI Clock Start_SDI_Clock(); // Notify the SD Bus driver of the PowerUp event SDHCDPowerUpDown(m_pHCContext, TRUE, FALSE, 0); // simulate a card ejection/insertion m_bReinsertTheCard = TRUE; SetEvent( m_hCardInsertInterruptEvent ); }
OnPowerDown:
首先调用SDHCDPowerUpDown通知SD总线驱动PowerDown事件,停止SDI时钟,调用DeinitializeHardware(继承类实现)进行硬件资源的释放.
void CSDIOControllerBase::OnPowerDown() { // Notify the SD Bus driver of the PowerDown event SDHCDPowerUpDown(m_pHCContext, FALSE, FALSE, 0); // Stop the SDI Clock Stop_SDI_Clock(); // Call DeinitializeHardware (By default, it does nothing, but OEM's may overwrite // this function to provide hardware specific configuration changes on PowerDown event) DeinitializeHardware( TRUE ); }
CSDIOControllerBase类就简单分析到这里,接下来来看看其继承类CSDIOController,里面实现了CSDIOControllerBase没有实现的几个纯虚函数.

你可能感兴趣的:(windows,api,command,null,resources,WinCE)