Windows CE的SD卡驱动包括总线驱动(bus driver),主控制器驱动(host controller driver)和客户端驱动(client driver).
总线驱动是客户端驱动和主控制器驱动之间的抽象管理层.提供了标准API允许SD卡客户端驱动运行在任何包含Sdbus.dll的Windows CE设备上.总线驱动独立于应用程序和客户端驱动,可以不加修改的移植到不同处理器平台.
主控制器驱动控制主控制器硬件,遵循主控制器驱动接口,能够被客户端驱动使用进行通信和设置参数.主控制器驱动提供了客户端驱动和主控制器实现之间的硬件抽象层.
客户端驱动通过其接口允许与SD卡设备通信.客户端驱动接口被设计抽象了SD总线的物理实现,同时提供了客户端驱动最大的弹性.客户端驱动接口允许客户端驱动实现从简单的,同步访问存储卡驱动到完整线程的异步通信驱动.(翻译自MS帮助,更多内容可参考MS帮助)
下面就结合SMDK2410的SDHC驱动来进行分析.
这个驱动实现了就是主控制器驱动(host controller driver).
主控制器驱动包含了硬件相关的代码,主要包含了controller, slot支持逻辑,包含了实际的硬件实现;实现SD/MMC传送与接收;可以是本地总线上的内存映射设备(如继承控制器),或者是外部总线如PCMCIA,PCI,USB;可以使用IO操作或者DMA.
SMDK2410 BSP下的SDHC是一个流接口驱动.由两部分组成:
SDHCBASE(sdhcmain.cpp,sdiocontrollerbase.cpp,sdiocontrollerbase.h,实现了标准的流接口函数);SDHC(sdiocontroller.cpp,sdiocontroller.h,实际的硬件操作函数)生成最终的dll,同时包含了注册表设置sdhc_sc2410.reg,导出函数定义sdhc_sc2410.def
我们先来看sdhcmain.cpp,里面实现如SDH_Init,,SDH_Deinit,SDH_Open等的流接口函数.
1.DllEntry
DllEntry是最终生成的dll入口函数,在source中定义:DLLENTRY=DllEntry
当加载dll时(DLL_PROCESS_ATTACH)首先调用DisableThreadLibraryCalls来禁止DLL_THREAD_ATTACH和DLL_THREAD_DETACH通知给hLibModule参数定义的dll,在不使用线程级跟踪(thread-level tracking)情况下可以减少工作代码空间.
然后调用SDInitializeCardLib来初始化SD卡库.该函数实现在Sdcardlib.lib(/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/SDCARD/SDCARDLIB).
如果调用SDInitializeCardLib成功,则调用SDHCDInitializeHCLib进一步初始化,如果调用失败则调用SDDeinitializeCardLib(实现在Sdhclib,/WINCE500/PUBLIC/COMMON/OAK/DRIVERS/SDCARD/SDHCLIB)取消初始化SD卡库.设置全局变量g_fRegisteredWithBusDriver表示未使用BusDriver注册.
卸载dll时(DLL_PROCESS_DETACH)调用SDHCDDeinitializeHCLib和SDDeinitializeCardLib来取消SD CardLib和HCLib的初始化.
BOOL DllEntry(HINSTANCE hInstance, ULONG Reason, LPVOID pReserved) { BOOL fRet = TRUE; if(Reason == DLL_PROCESS_ATTACH) { DEBUGREGISTER(hInstance); DisableThreadLibraryCalls( (HMODULE) hInstance ); if( !SDInitializeCardLib() ) { fRet = FALSE; } else if( !SD_API_SUCCESS( SDHCDInitializeHCLib() ) ) { SDDeinitializeCardLib(); fRet = FALSE; } g_fRegisteredWithBusDriver = FALSE; } if(Reason == DLL_PROCESS_DETACH) { SDHCDDeinitializeHCLib(); SDDeinitializeCardLib(); } return(TRUE); }
2.SDH_Init
首先调用SDHCDAllocateContext来分配一段HC的上下文,如果成功就调用CreateSDIOController创建SD Host Controller对象CSDIOController类对象,CSDIOController是(CSDIOControllerBase的继承类).并将其赋值给pHostContext->pHCSpecificContext.接着调用InterpretCapabilities(CSDIOControllerBase成员函数)从注册表获得SD Host Controller信息.该函数的具体实现稍后在看.
最后调用SDHCDRegisterHostController来Host Controller.设置g_fRegisteredWithBusDriver注册标志为TRUE.返回pController.如果上述操作中任何一项失败,则进入Exit调用诸如SDHCDDeregisterHostController和SDHCDDeleteContext来取消注册和删除HC对象(上下文).
extern "C" DWORD SDH_Init(DWORD dwContext) { DWORD dwRet = 0; // return value PSDCARD_HC_CONTEXT pHostContext = NULL; // new HC context SD_API_STATUS status; // SD status LPCTSTR pszActiveKey = (LPCTSTR) dwContext; CSDIOControllerBase* pController = NULL; DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("SDHC +Init/n"))); ASSERT( g_fRegisteredWithBusDriver == FALSE ); // Allocate the context status = SDHCDAllocateContext(SDHCD_SLOTS/*, sizeof(SDHCD_HARDWARE_CONTEXT)*/, &pHostContext); if(!SD_API_SUCCESS(status)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD: Failed to allocate context : 0x%08X /n"), status)); goto EXIT; } // Create the SD Host Controller object pController = CreateSDIOController( pHostContext ); if( pController == NULL ) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHC Failed to allocate SD Host Controller object/n"))); goto EXIT; } // Set our extension pHostContext->pHCSpecificContext = pController; // Read SD Host Controller Info from registry. if (!pController->InterpretCapabilities((LPCTSTR)dwContext)) { goto EXIT; } // now register the host controller status = SDHCDRegisterHostController(pHostContext); if(!SD_API_SUCCESS(status)) { DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD: Failed to register host controller: %0x08X /n"),status)); goto EXIT; } g_fRegisteredWithBusDriver = TRUE; // return the controller context dwRet = (DWORD)pController; EXIT: if( dwRet == 0 ) { if( pHostContext ) { // deregister the host controller if (g_fRegisteredWithBusDriver) { SDHCDDeregisterHostController(pHostContext); g_fRegisteredWithBusDriver = FALSE; } // delete the SD Host Controller object if( pController ) { delete pController; } // cleanup the host context SDHCDDeleteContext(pHostContext); } } DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("SDHC -Init/n"))); return dwRet; }
3.SDH_PreDeinit
SDH_PreDeinit首先获得HC Context,然后调用CSDIOControllerBase的成员函数PreDeinit,最后调用SDHCDDeregisterHostController解除HC Context的注册.
extern "C" BOOL SDH_PreDeinit(DWORD hDeviceContext) { CSDIOControllerBase *pController = (CSDIOControllerBase*)hDeviceContext; if( g_fRegisteredWithBusDriver ) { PSDCARD_HC_CONTEXT pHostContext = pController->GetHostContext(); pController->PreDeinit(); // deregister the host controller SDHCDDeregisterHostController(pHostContext); g_fRegisteredWithBusDriver = FALSE; } return TRUE; }
4.SDH_Deinit
SDH_Deinit首先根据g_fRegisteredWithBusDriver来判断host controller有没被解除注册,没有就再次调用SDHCDDeregisterHostController
然后删除SD Host Controller对象,清除host context.
extern "C" BOOL SDH_Deinit(DWORD hDeviceContext) { CSDIOControllerBase *pController = (CSDIOControllerBase*)hDeviceContext; PSDCARD_HC_CONTEXT pHostContext = pController->GetHostContext(); if( g_fRegisteredWithBusDriver ) { // deregister the host controller SDHCDDeregisterHostController(pHostContext); g_fRegisteredWithBusDriver = FALSE; } // delete the SD Host Controller object delete pController; // Cleanup the host context SDHCDDeleteContext(pHostContext); return TRUE; }
5..SDH_Open
SDH_Open返回CSDIOControllerBase类对象pController.
extern "C" DWORD SDH_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode) { DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDHCD: +-SDH_Open/n"))); CSDIOControllerBase *pController = (CSDIOControllerBase*)hDeviceContext; return (DWORD) pController; }
6.SDH_IOControl,SDH_Close
SDH_IOControl,SDH_Close未做任何工作,直接返回.
7.SDH_PowerDown,SDH_PowerUp
SDH_PowerDown,SDH_PowerUp分别调用CSDIOControllerBase类的成员函数OnPowerDown和OnPowerUp.
接下来就来看看CSDIOControllerBase和其继承类CSDIOController的实现.