wince5.0下S3C2412SD卡驱动分析

网上对SD驱动总体结构的分析已经很多了,SD卡驱动一般采用微软的三层结构,最上层是Client层,可以有多个SD卡或者MMC卡调用;最下层是硬件控制层,直接读写寄存器;中间层是Bus层,Bus层作为Client层和HC层的中间桥梁,传输读写等命令。幸运的是,微软已经为我们编写好了Client层和Bus层,我们一般不要去修改,我们主要分析HC代码。不同的板子有不同的HC,我们看看S3C2413的HC层源代码,位于%WINCEROOT%/PLATFORM/SMDK2413/Src/Drivers/SDHC下面。
先分析sdiocontroller.cpp,看CustomSetup函数:

/*打开注册表*/
HKEY hKeyDevice = OpenDeviceKey(pszRegistryPath);

/*提取注册表"CardDetectGPIO"键值,我设置为"G"了,意思是选择G端口来检测卡*/
LPCTSTR pszCardDetectGPIO = regDevice.ValueSZ( CARD_DETECT_GPIO_TEXT );

/*提取注册表"CardDetectMask"键值,我设置为dword:100了,意思是选择G端口的8位,即EINT16来检测卡*/
m_dwCardDetectMask = regDevice.ValueDW( CARD_DETECT_MASK_TEXT );

/*提取注册表"CardDetectFlag"键值,我设置为dword:0了,意思是选择将GPG8置0*/
m_dwCardDetectFlag = regDevice.ValueDW( CARD_DETECT_FLAG_TEXT );

/*提取注册表"CardDetectControlMask"键值,我设置为dword:fffcffff了*/
m_dwCardDetectControlMask=regDevice.ValueDW( CARD_DETECT_CONTROL_MASK_TEXT );

/*提取注册表"CardDetectControlFlag"键值,我设置为dword:0*/
m_dwCardDetectControlFlag=regDevice.ValueDW( CARD_DETECT_CONTROL_FLAG_TEXT );

/*提取注册表"CardDetectPullupMask"键值,我设置为dword:fffffeff*/
m_dwCardDetectPullupMask=regDevice.ValueDW( CARD_DETECT_PULLUP_MASK_TEXT );

/*提取注册表"CardDetectPullupFlag"键值,我设置为dword:100*/
m_dwCardDetectPullupFlag=regDevice.ValueDW( CARD_DETECT_PULLUP_FLAG_TEXT );

/*提取注册表"CardReadWriteGPIO"键值,我设置为"H",意思是选择H端口来读写*/
LPCTSTR pszCardReadWriteGPIO=
regDevice.ValueSZ( CARD_READWRITE_GPIO_TEXT );

/*跟前面类似,不再赘述*/
m_dwCardReadWriteMask = regDevice.ValueDW( CARD_READWRITE_MASK_TEXT );
m_dwCardReadWriteFlag = regDevice.ValueDW( CARD_READWRITE_FLAG_TEXT );
m_dwCardReadWriteControlMask=regDevice.ValueDW( CARD_READWRITE_CONTROL_MASK_TEXT );
m_dwCardReadWriteControlFlag=regDevice.ValueDW( CARD_READWRITE_CONTROL_FLAG_TEXT );
m_dwCardReadWritePullupMask=regDevice.ValueDW( CARD_READWRITE_PULLUP_MASK_TEXT );
m_dwCardReadWritePullupFlag=regDevice.ValueDW( CARD_READWRITE_PULLUP_FLAG_TEXT );

重点还是放在硬件初始化函数InitializeHardware:

前面已经提到,我们在注册表里面设置"CardReadWriteGPIO"为"H",m_chCardReadWriteGPIO就为H。

/*设置GPHCON寄存器和GPHDN寄存器,前者是配置端口H的pin的寄存器,根据datasheet,后者是H端口Pull-down function的允许禁止寄存器,至于Pull-down function是什么意思,我也不清楚,先不管,继续在黑暗中探索*/
case 'H':
vm_pIOPreg->GPHCON = ( vm_pIOPreg->GPHCON & m_dwCardReadWriteControlMask ) | m_dwCardReadWriteControlFlag;
vm_pIOPreg->GPHDN = ( vm_pIOPreg->GPHDN & m_dwCardReadWritePullupMask ) | m_dwCardReadWritePullupFlag;
break;

 
前面已经提到,我们在注册表里面设置"CardDetectGPIO"为"G",m_chCardDetectGPIO就为G。
/*设置GPGDN寄存器*/
case 'G':
vm_pIOPreg->GPGDN = ( vm_pIOPreg->GPGDN & m_dwCardDetectPullupMask ) | m_dwCardDetectPullupFlag;
break;

 我们再来看sdiocontrollerbase.cpp的源代码,看函数Initialize:

/*SD_API_STATUS 在sdcarddk.h里面定义为LONG,SD_API_STATUS_SUCCESS被定义为0*/
SD_API_STATUS status = SD_API_STATUS_SUCCESS;   // intermediate status

/*初始化临界变量m_ControllerCriticalSection*/
InitializeCriticalSection(&m_ControllerCriticalSection);

/*给2413的IO端口分配内存*/
vm_pIOPreg = (S3C2413_IOPORT_REG *)VirtualAlloc(0, sizeof(S3C2413_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
/*把刚才分配的虚拟内存映射成物理内存*/
VirtualCopy((PVOID)vm_pIOPreg, (PVOID)(S3C2413_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2413_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)

/*给2413的SDI寄存器分配内存*/
vm_pSDIReg = (S3C2413_SDI_REG *)VirtualAlloc(0, sizeof(S3C2413_SDI_REG), MEM_RESERVE, PAGE_NOACCESS);

/*把刚才分配给SDI的虚拟内存映射成物理内存*/
VirtualCopy((PVOID)vm_pSDIReg, (PVOID)(S3C2413_BASE_REG_PA_SDI >> 8), sizeof(S3C2413_SDI_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)

/*给2413的时钟电源寄存器分配内存*/
vm_pCLKPWR=(S3C2413_CLKPWR_REG*)VirtualAlloc(0, sizeof(S3C2413_CLKPWR_REG), MEM_RESERVE, PAGE_NOACCESS);

/*把刚才分配给时钟电源寄存器映射成为物理内存*/
VirtualCopy((PVOID)vm_pCLKPWR,(PVOID)(S3C2413_BASE_REG_PA_CLOCK_POWER >> 8), sizeof(S3C2413_CLKPWR_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)

/*给2413的DMA寄存器分配虚拟内存*/
vm_pDMAreg = (S3C2413_DMA_REG *)VirtualAlloc(0, sizeof(S3C2413_DMA_REG), MEM_RESERVE, PAGE_NOACCESS);

/*把刚才分配给DMA寄存器的虚拟内存映射成物理内存*/
VirtualCopy((PVOID)vm_pDMAreg, (PVOID)(S3C2413_BASE_REG_PA_DMA >> 8), sizeof(S3C2413_DMA_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)

/*分配内存给DAM以传输数据使用*/
m_pDMABuffer=(PBYTE)HalAllocateCommonBuffer(&dmaAdapter,MAXIMUM_DMA_TRANSFER_SIZE, &m_pDMABufferPhys, FALSE );

/* MMC_Hardware_PowerUp函数就是往CLKCON寄存器的9位置位,给SDI控制器提供电源*/
MMC_Hardware_PowerUp();

/*设置GPIO为SDI模式,允许上拉寄存器*/
vm_pIOPreg->GPEDN  &= 0xF83F;
vm_pIOPreg->GPECON |= 0x2AA800;

/*设置为默认时钟频率*/
SetClockRate(SD_DEFAULT_CARD_ID_CLOCK_RATE);
/*设置SDICON SDIFSTA SDIBSIZE SDIDTIMER寄存器*/
vm_pSDIReg->SDICON |= LITTLE_ENDIAN_BYTE_ORDER;   
vm_pSDIReg->SDIFSTA |= FIFO_RESET;              
vm_pSDIReg->SDIBSIZE = BYTES_PER_SECTOR;
vm_pSDIReg->SDIDTIMER = MAX_DATABUSY_TIMEOUT;
   

/*创建一个事件等待卡插入的中断*/
m_hCardInsertInterruptEvent = CreateEvent(NULL, FALSE, FALSE,NULL); 

/*创建一个为侦测卡的插入创建一个线程*/
m_hCardInsertInterruptThread = CreateThread(NULL,
0,                          (LPTHREAD_START_ROUTINE)SD_CardDetecThread,
                                            this, 
0,
&threadID);

/*中断初始化,绑定m_hCardInsertInterruptEvent事件给中断m_dwSDDetectSysIntr*/
InterruptInitialize (m_dwSDDetectSysIntr, m_hCardInsertInterruptEvent,NULL, 0)

然后是对信号响应、DMA数据传输的中断的设置,与上雷同。InitializeHardware()函数为初始化硬件操作,在本文的开头已经分析过了。下面还有一个关键的函数SlotOptionHandler。
SD_SLOT_OPTION_CODE是一个枚举,定义在sdhcd.h里面:
typedef enum _SD_SLOT_OPTION_CODE {
    SDHCDNop = -1,
    SDHCDSetSlotPower,          // set slot power, takes a DWORD for the power bit mask
    SDHCDSetSlotInterface,   // set slot interface, takes a SD_CARD_INTERFACE structure
    SDHCDEnableSDIOInterrupts,      // enable SDIO interrupts on the slot, no parameters
    SDHCDDisableSDIOInterrupts,     // disable SDIO interrupts on the slot, no parameters
    SDHCDAckSDIOInterrupt,          // acknowledge that the SDIO interrupt was handled, no parameters
    SDHCDGetWriteProtectStatus,                       // get Write protect status. Updates SD_CARD_INTERFACE structure
    SDHCDQueryBlockCapability,      // query whether HC supports requested block length,
                                    // takes SD_HOST_BLOCK_CAPABILITY structure
    SDHCDSetClockStateDuringIdle,   // set the clock state(on or off) during the idle state
    SDHCDSetSlotPowerState, // set the slot power state, takes a CEDEVICE_POWER_STATE
    SDHCDGetSlotPowerState, // get the slot power state, takes a CEDEVICE_POWER_STATE
    SDHCDWakeOnSDIOInterrupts,   // wake on SDIO interrupts in D3, takes a BOOL
    SDHCDGetSlotInfo,    // get info on a specific slot, takes a PSDCARD_HC_SLOT_INFO
    SDHCDSetSlotInterfaceEx,      // set slot interface, takes a SD_CARD_INTERFACE_EX structure
    SDHCDSlotOptionCount    // count of valid slot option codes
} SD_SLOT_OPTION_CODE, *PSD_SLOT_OPTION_CODE;

/*看来电源是不能随便改变的*/
case SDHCDSetSlotPower:
// Nothing to do because this system only operates at the reported 3.3V
break;

接下来我们要搞清楚pData究竟是个什么东西?
它是一个PSD_CARD_INTERFACE类型的结构体,PSD_CARD_INTERFACE定义在sdcardddk.h里面:
// structure for information about a card's interface
typedef struct _SD_CARD_INTERFACE {
    SD_INTERFACE_MODE   InterfaceMode;  // interface mode
    ULONG               ClockRate;      // clock rate
    BOOL                WriteProtected; // write protect flag (SD Memory cards)
} SD_CARD_INTERFACE, *PSD_CARD_INTERFACE;

pData是被函数SlotOptionHandler传入的,在SDHCDSlotOptionHandler函数的定义里又用到了SlotOptionHandler函数,具体在什么地方确定pData的值呢?这是个问题!

/*设置总线宽度和时钟频率*/
case SDHCDSetSlotInterface:
    // First set the bus width
   if(((PSD_CARD_INTERFACE)pData)->InterfaceMode == SD_INTERFACE_SD_4BIT)
   {
       Set_SDI_Bus_Width_4Bit();
   }else
   {
       Set_SDI_Bus_Width_1Bit();
   }
// Next, set the clock rate
   ((PSD_CARD_INTERFACE)pData)->ClockRate = SetClockRate(((PSD_CARD_INTERFACE)pData)->ClockRate);
   break;

/*打开SDIO中断*/
case SDHCDEnableSDIOInterrupts:                                
    Enable_SDIO_Interrupts();
break;

/*关掉SDIO中断*/
case SDHCDDisableSDIOInterrupts:                               
    Disable_SDIO_Interrupts();
    break;

/*清楚SDIO中断悬置位*/
case SDHCDAckSDIOInterrupt:                                    
           

    Ack_SDIO_Interrupts();
    InterruptDone(m_dwSDIOSysIntr);
break;

/*保存写保护状态*/
case SDHCDGetWriteProtectStatus:
    ((PSD_CARD_INTERFACE)pData)->WriteProtected = IsCardWriteProtected();
break;

/*修正读写块大小设置*/
case SDHCDQueryBlockCapability:
 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:
    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;
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));
SDHCDSetDesiredSlotVoltage(pSlotInfo, SD_VDD_WINDOW_3_2_TO_3_3);
SDHCDSetMaxClockRate(pSlotInfo, MAX_SDI_BUS_TRANSFER_SPEED); 
SDHCDSetPowerUpDelay(pSlotInfo, 300);
}
break;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值