接下来我们来看看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没有实现的几个纯虚函数