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

来源:互联网 发布:大典太光世数据 编辑:程序博客网 时间:2024/05/21 09:40

接下来我们来看看CSDIOControllerBase类,该类实现了主控制器驱动的硬件实现,定义了很多成员变量和函数,如有错误,欢迎指正.
CSDIOControllerBase原型如下:

其中有几个纯虚函数是由继承类实现的(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
 
2.~CSDIOControllerBase
未做任何工作.

3.PreDeinit
这个函数被SDH_PreDeinit调用,m_bDriverShutdown为FALSE时调用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

5.Deinitialize
Deinitialize用来关闭Initialize创建的事件IST线程,释放DMA buffer,关闭SDI power等

6.CancelIoHandler
CancelIoHandler被SDHCDCancelIoHandler调用.首先调用Stop_SDI_Hardware设置SDIDCON强制停止数据传输.调用SDHCDReleaseHCLock释放lock,最后调用SDHCDIndicateBusRequestComplete使用Cancel状态(SD_API_STATUS_CANCELED)来完成Bus请求.

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参数,如电压,时钟频率,上电延时等.

8.BusRequestHandler
BusRequestHandler被SDHCDBusRequestHandler调用,用来处理总线请求.
首先复位FIFO和状态寄存器,然后使能SDI CLOCK,计算要传输数据大小,判断是否DMA传输以及是否4字节对齐,4字节整数倍来进行DMA传输(SetupDmaXfer)或者轮询IO传输(SetupPollingXfer).
接着判断传输的是单独命令还是命令和数据,第一次传输命令时需延时80个clock周期.SendCommand最后一个参数表示是传输命令(FALSE)还是命令和数据(TRUE).
最后设置设置事件m_hResponseReceivedEvent来通知传输IST命令应答发生.

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).

10.IOInterruptIstThread
被SD_IOInterruptIstThread调用,对应于句柄m_hSDIOInterruptThread.同样首先设置线程优先级(从注册表中获取"SDIO_IST_Priority"=dword:97),然后等待m_hSDIOInterruptEvent事件发生,如果事件发生同时卡存在的话,调用SDHCDIndicateSlotStateChange通知总线驱动SD卡中断发生.

11.CardDetectThread
被SD_CardDetectThread调用.首先设置线程优先级(从注册表中获取"CardDetect_Thread_Priority"=dword:98"),然后等待m_hCardInsertInterruptEvent事件,调用IsCardPresent监测卡是否插入.如果卡拔出,调用SDHCDIndicateSlotStateChange通知DeviceEjected,否则卡插入,进行SDI寄存器初始化,设置clock rate(100KHz),启动SDI clock,调用SDHCDIndicateSlotStateChange通知DeviceInserted.

12.SendCommand
在BusRequestHandler中被调用,首先清除SDICSTA状态标志位,设置SDICARG命令参数寄存器.判断命令是否带数据设置SDICCON.根据不同的Response类型SDICCON进行不同设置.NoResponse时,写命令到SDICCON并发送命令,并确定发送完成.Short response时,SDICCON设置WAIT_FOR_RESPONSE.ResponseR2时,SDICCON设置LONG_RESPONSE | WAIT_FOR_RESPONSE.

13.GetCommandResponse
该函数用来获取命令应答,在TransferIstThread被调用.读取SDICSTA直到命令应答接收,如果有错误状态就返回错误.然后根据不同的应答类型分别读取SDIRSP0,SDIRSP1,SDIRSP2,SDIRSP3,具体格式参加代码注释.

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

15.IsCardBusy
检查Card是否处在Busy状态.检查SDICSTA和SDIDSTA状态寄存器,COMMAND_IN_PROGRESS,DATA_TRANSMIT_IN_PROGRESS,DATA_RECIEVE_IN_PROGRESS,READ_WAIT_REQUEST_OCCURE状态发生时,Card处于Busy状态.

16.SetClockRate
设置SDI clock时钟频率.首先检查参数正确性,频率最大为25MHz.如果输入MMC全速频率20MHz,由于2410在20MHz会有问题,所以设置成20MHz,然后计算分频值prescale = ((PCLK / (2*baud_rate)) - 1,然后确保SDI时钟处于停止状态,最后设置SDIPRE寄存器设置分配值,并启动SDI时钟.

17.PollingTransmit
用来轮询发送数据.首先判断一些错误状态是否发生,如卡不再插槽,FIFO Fail,CRC error等就返回false.状态正常则读取SDIFSTA看FIFO能否接收更多数据.可以就向SDIDAT写数据.直至FIFO满为止.然后监测数据是否写完,并设置DATA_TRANSMIT_FINISHED.

18.PollingReceive
轮询接收数据.首先判断一些错误状态是否发生,没有的话读SDIFSTA寄存器看是否有数据,有的话读取数据到缓冲区中.

19.SetupPollingXfer
设置IO端口来初始化轮询.检查参数,Reset FIFO,然后根据传输类型(SD_READ,SD_WRITE,SD_COMMAND)来设置SDIBSIZE和SDIDCON寄存器.

20.SD_CardDetectThread,SD_IOInterruptIstThread,SD_TransferIstThread
分别对应于CardDetectThread,SD_IOInterruptIstThread,SD_TransferIstThread

21.SDHCDInitialize,SDHCDDeinitialize,SDHCDCancelIoHandler,SDHCDBusRequestHandler,SDHCDSlotOptionHandler分别对应于Initialize,Deinitialize,CancelIoHandler,BusRequestHandler,SlotOptionHandler,这几个SDHCD handler在InterpretCapabilities被SDHCDSetControllerInitHandler,SDHCDSetControllerDeinitHandler,,SDHCDSetCancelIOHandler,SDHCDSetBusRequestHandler,SDHCDSetSlotOonHandler注册.实际上就是将这几个函数指针赋值给pHCContext对应的函数指针成员.

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的成员赋值.

23.GetHostContext
返回m_pHCContext

24.MMC_Hardware_PowerUp,MMC_Hardware_PowerDown
启动禁止SDI时钟,设置CLKON寄存器bit9(Control PCLK into SDI interface block)

25.Stop_SDI_Hardware
停止数据传输,设置SDIDCON bit14强制停止数据传输(Determine whether data transfer stop by force or not)

26.Set_SDI_Bus_Width_1Bit,Set_SDI_Bus_Width_4Bit,Get_SDI_Bus_Width
设置和获取bus位宽(1bit或4bit)

27.Wait_80_SDI_Clock_Cycles
延时,这里调用sleep(1)延时约1ms


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状态.

29.Enable_SDIO_Interrupts,Disable_SDIO_Interrupts,Is_SDIO_Interrupt_Enabled,Is_SDIO_Interrupt_Enabled作用分别为使能/禁止SDIO中断,返回SDIO中断状态,清除中断标志.

30.Enable_SDIO_DMA_Channel,Disable_SDIO_DMA_Channel
使能/禁止对应DMA通道(m_dwDMAChannel)

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.

OnPowerDown:
首先调用SDHCDPowerUpDown通知SD总线驱动PowerDown事件,停止SDI时钟,调用DeinitializeHardware(继承类实现)进行硬件资源的释放.

CSDIOControllerBase类就简单分析到这里,接下来来看看其继承类CSDIOController,里面实现了CSDIOControllerBase没有实现的几个纯虚函数.

原创粉丝点击