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;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章