Windows CE SDHC驱动简析(1)-驱动架构(基于WinCE5.0 SMDK2410 BSP的SDHC驱动)

时间:2022-02-23 17:27:27

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的初始化.

[c-sharp] view plaincopy
  1. BOOL DllEntry(HINSTANCE hInstance, ULONG Reason, LPVOID pReserved)  
  2. {  
  3.     BOOL fRet = TRUE;  
  4.   
  5.     if(Reason == DLL_PROCESS_ATTACH)   
  6.     {  
  7.         DEBUGREGISTER(hInstance);  
  8.         DisableThreadLibraryCalls( (HMODULE) hInstance );  
  9.   
  10.         if( !SDInitializeCardLib() )  
  11.         {  
  12.             fRet = FALSE;  
  13.         }  
  14.         else if( !SD_API_SUCCESS( SDHCDInitializeHCLib() ) )   
  15.         {  
  16.             SDDeinitializeCardLib();  
  17.             fRet = FALSE;  
  18.         }  
  19.   
  20.         g_fRegisteredWithBusDriver = FALSE;  
  21.     }  
  22.   
  23.     if(Reason == DLL_PROCESS_DETACH)   
  24.     {     
  25.         SDHCDDeinitializeHCLib();  
  26.         SDDeinitializeCardLib();  
  27.     }  
  28.   
  29.     return(TRUE);  
  30. }  

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对象(上下文).
[c-sharp] view plaincopy
  1. extern "C"  
  2. DWORD SDH_Init(DWORD dwContext)  
  3. {  
  4.     DWORD                   dwRet = 0;           // return value      
  5.     PSDCARD_HC_CONTEXT      pHostContext = NULL; // new HC context  
  6.     SD_API_STATUS           status;              // SD status  
  7.     LPCTSTR pszActiveKey = (LPCTSTR) dwContext;  
  8.     CSDIOControllerBase* pController = NULL;  
  9.   
  10.     DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("SDHC +Init/n")));  
  11.   
  12.     ASSERT( g_fRegisteredWithBusDriver == FALSE );  
  13.   
  14.     // Allocate the context  
  15.     status = SDHCDAllocateContext(SDHCD_SLOTS/*, sizeof(SDHCD_HARDWARE_CONTEXT)*/, &pHostContext);  
  16.   
  17.     if(!SD_API_SUCCESS(status))   
  18.     {  
  19.         DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD: Failed to allocate context : 0x%08X /n"), status));  
  20.         goto EXIT;  
  21.     }  
  22.   
  23.     // Create the SD Host Controller object  
  24.     pController = CreateSDIOController( pHostContext );  
  25.     if( pController == NULL ) {  
  26.         DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHC Failed to allocate SD Host Controller object/n")));  
  27.         goto EXIT;  
  28.     }  
  29.   
  30.     // Set our extension  
  31.     pHostContext->pHCSpecificContext = pController;  
  32.   
  33.     // Read SD Host Controller Info from registry.  
  34.     if (!pController->InterpretCapabilities((LPCTSTR)dwContext)) {  
  35.         goto EXIT;  
  36.     }  
  37.   
  38.     // now register the host controller   
  39.     status = SDHCDRegisterHostController(pHostContext);  
  40.   
  41.     if(!SD_API_SUCCESS(status))   
  42.     {  
  43.         DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("SDHCD: Failed to register host controller: %0x08X /n"),status));  
  44.         goto EXIT;  
  45.     }  
  46.     g_fRegisteredWithBusDriver = TRUE;  
  47.   
  48.     // return the controller context  
  49.     dwRet = (DWORD)pController;  
  50.       
  51. EXIT:  
  52.     if( dwRet == 0 )  
  53.     {  
  54.         if( pHostContext )   
  55.         {  
  56.             // deregister the host controller  
  57.             if (g_fRegisteredWithBusDriver)   
  58.             {  
  59.                 SDHCDDeregisterHostController(pHostContext);  
  60.                 g_fRegisteredWithBusDriver = FALSE;  
  61.             }  
  62.   
  63.             // delete the SD Host Controller object  
  64.             if( pController )  
  65.             {  
  66.                 delete pController;  
  67.             }  
  68.   
  69.             // cleanup the host context  
  70.             SDHCDDeleteContext(pHostContext);  
  71.         }  
  72.     }  
  73.   
  74.     DEBUGMSG(SDCARD_ZONE_INIT, (TEXT("SDHC -Init/n")));  
  75.       
  76.     return dwRet;  
  77. }  
  
3.SDH_PreDeinit
SDH_PreDeinit首先获得HC Context,然后调用CSDIOControllerBase的成员函数PreDeinit,最后调用SDHCDDeregisterHostController解除HC Context的注册.
[c-sharp] view plaincopy
  1. extern "C"  
  2. BOOL SDH_PreDeinit(DWORD hDeviceContext)  
  3. {  
  4.     CSDIOControllerBase *pController = (CSDIOControllerBase*)hDeviceContext;  
  5.   
  6.     if( g_fRegisteredWithBusDriver )  
  7.     {  
  8.         PSDCARD_HC_CONTEXT pHostContext = pController->GetHostContext();  
  9.   
  10.         pController->PreDeinit();  
  11.   
  12.         // deregister the host controller  
  13.         SDHCDDeregisterHostController(pHostContext);  
  14.   
  15.         g_fRegisteredWithBusDriver = FALSE;  
  16.     }  
  17.   
  18.     return TRUE;  
  19. }  

4.SDH_Deinit
SDH_Deinit首先根据g_fRegisteredWithBusDriver来判断host controller有没被解除注册,没有就再次调用SDHCDDeregisterHostController
然后删除SD Host Controller对象,清除host context.

[c-sharp] view plaincopy
  1. extern "C"  
  2. BOOL SDH_Deinit(DWORD hDeviceContext)  
  3. {  
  4.     CSDIOControllerBase *pController = (CSDIOControllerBase*)hDeviceContext;  
  5.     PSDCARD_HC_CONTEXT pHostContext = pController->GetHostContext();  
  6.   
  7.     if( g_fRegisteredWithBusDriver )  
  8.     {  
  9.         // deregister the host controller  
  10.         SDHCDDeregisterHostController(pHostContext);  
  11.   
  12.         g_fRegisteredWithBusDriver = FALSE;  
  13.     }  
  14.   
  15.     // delete the SD Host Controller object  
  16.     delete pController;  
  17.   
  18.     // Cleanup the host context  
  19.     SDHCDDeleteContext(pHostContext);  
  20.   
  21.     return TRUE;  
  22. }  

5..SDH_Open
SDH_Open返回CSDIOControllerBase类对象pController.

[c-sharp] view plaincopy
  1. extern "C"  
  2. DWORD SDH_Open(DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode)  
  3. {  
  4.     DEBUGMSG(SDCARD_ZONE_FUNC, (TEXT("SDHCD: +-SDH_Open/n")));  
  5.     CSDIOControllerBase *pController = (CSDIOControllerBase*)hDeviceContext;  
  6.     return (DWORD) pController;  
  7. }  

6.SDH_IOControl,SDH_Close
SDH_IOControl,SDH_Close未做任何工作,直接返回.

7.SDH_PowerDown,SDH_PowerUp
SDH_PowerDown,SDH_PowerUp分别调用CSDIOControllerBase类的成员函数OnPowerDown和OnPowerUp.

接下来就来看看CSDIOControllerBase和其继承类CSDIOController的实现