📄 sdcontrol.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// Copyright (c) 2002 BSQUARE Corporation. All rights reserved.
// DO NOT REMOVE --- BEGIN EXTERNALLY DEVELOPED SOURCE CODE ID 40973--- DO NOT REMOVE
//
// Module Name:
//
// SDControl.c
//
// Abstract:
//
// PXA27X SDIO controller implementation
//
// Notes:
//
///////////////////////////////////////////////////////////////////////////////
//#define EXTENSIVE_DEBUGGING
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <celog.h>
#include <giisr.h>
#include "SDCardDDK.h"
#include "SDHCD.h"
#include "SD.h"
#ifdef CELOGENABLE
#define _CeLogEnable TRUE
#else
#define _CeLogEnable FALSE
#endif
// prototypes
PVOID VirtualAllocCopy(unsigned size,char *str,PVOID pVirtualAddress);
DWORD SDControllerIstThread(PSDH_HARDWARE_CONTEXT pHCDevice);
DWORD SDDMAIstThread(PSDH_HARDWARE_CONTEXT pHCDevice);
#ifdef DEBUG
void DumpRegisters(PSDH_HARDWARE_CONTEXT pController);
void DumpGPIORegisters(PSDH_HARDWARE_CONTEXT pController);
#endif
BOOL PrepareDmaTransfer( PSDH_HARDWARE_CONTEXT pController, PSD_BUS_REQUEST pRequest );
#ifdef DEBUG
#define HEXBUFSIZE 1024
char szHexBuf[HEXBUFSIZE];
#define TRANSFER_SIZE(pRequest) ((pRequest)->BlockSize * (pRequest)->NumBlocks)
char* HexDisplay( BYTE *pBuffer, DWORD dwLength )
{
DWORD dwTemp = 0;
while( dwTemp < dwLength && (dwTemp < (HEXBUFSIZE / 2 - 1) ) )
{
szHexBuf[dwTemp*2] = pBuffer[dwTemp] / 16;
szHexBuf[dwTemp*2+1] = pBuffer[dwTemp] % 16;
if( szHexBuf[dwTemp*2] < 10 )
szHexBuf[dwTemp*2] += '0';
else
szHexBuf[dwTemp*2] += 'a' - 10;
if( szHexBuf[dwTemp*2+1] < 10 )
szHexBuf[dwTemp*2+1] += '0';
else
szHexBuf[dwTemp*2+1] += 'a' - 10;
dwTemp++;
}
szHexBuf[dwTemp*2] = 0;
return szHexBuf;
}
void DumpHexDisplay( BYTE *pBuffer, DWORD dwLength )
{
const int lsize = 64;
char szBuffer[65];
char* pszData;
int l = 0;
int total_l = dwLength / lsize;
int r = dwLength % lsize;
pszData = HexDisplay( pBuffer, dwLength );
for( l = 0; l < total_l; l++ )
{
strncpy( szBuffer, pszData + l * lsize, lsize );
szBuffer[lsize] = 0;
DEBUGMSG( TRUE, (TEXT("%S\r\n"), szBuffer ) );
}
if( r )
{
strncpy( szBuffer, pszData + l * lsize, r );
szBuffer[r] = 0;
DEBUGMSG( TRUE, (TEXT("%S\r\n"), szBuffer ) );
}
}
#endif
__inline void WRITE_MMC_REGISTER_DWORD(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset, DWORD Value)
{
BYTE *pRegBaseAddr, *regAddr;
volatile DWORD *pdwRegAddr;
pRegBaseAddr = (BYTE*)(pHc->pSDMMCRegisters);
regAddr = pRegBaseAddr + RegOffset;
pdwRegAddr = (DWORD*)regAddr;
*pdwRegAddr = Value;
}
__inline DWORD READ_MMC_REGISTER_DWORD(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset)
{
BYTE *pRegBaseAddr, *regAddr;
volatile DWORD *pdwRegAddr;
pRegBaseAddr = (BYTE*)(pHc->pSDMMCRegisters);
regAddr = pRegBaseAddr + RegOffset;
pdwRegAddr = (DWORD*)regAddr;
return (*pdwRegAddr);
}
#define IS_PROGRAM_DONE(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_PROGRAM_DONE)
#define IS_TRANSFER_DONE(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_DATA_TRANSFER_DONE)
//#define RX_FIFO_FULL(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_RCV_FIFO_FULL)
//#define TX_FIFO_EMPTY(pHc) (READ_MMC_REGISTER_DWORD((pHc), MMC_STAT) & MMC_STAT_XMIT_FIFO_EMPTY)
#define TRANSFER_IS_WRITE(pRequest) ((SD_WRITE == (pRequest)->TransferClass))
#define TRANSFER_IS_READ(pRequest) ((SD_READ == (pRequest)->TransferClass))
BOOL CLOCK_IS_ON(PSDH_HARDWARE_CONTEXT pHc)
{
if( READ_MMC_REGISTER_DWORD( pHc, MMC_STAT ) & MMC_STAT_CLOCK_ENABLED )
{
return TRUE;
}
else
{
return FALSE;
}
}
__inline void READ_MOD_WRITE_MMC_REGISTER_AND_OR(PSDH_HARDWARE_CONTEXT pHc, DWORD RegOffset, DWORD AndValue, DWORD OrValue)
{
DWORD regValue;
regValue = READ_MMC_REGISTER_DWORD(pHc, RegOffset);
regValue &= (AndValue);
regValue |= (OrValue);
DEBUGMSG(SDCARD_ZONE_INFO, (TEXT("SHCDriver: - Setting MMC Reg 0x%x to 0x%x\r\n"), RegOffset, regValue));
WRITE_MMC_REGISTER_DWORD(pHc, RegOffset, regValue);
}
__inline void WRITE_MMC_IMASK_DWORD(PSDH_HARDWARE_CONTEXT pHc, DWORD Value)
{
EnterCriticalSection(&(pHc->intrRegCriticalSection));
WRITE_MMC_REGISTER_DWORD( pHc, MMC_IMASK, Value);
LeaveCriticalSection(&(pHc->intrRegCriticalSection));
}
__inline DWORD READ_MMC_IMASK_DWORD(PSDH_HARDWARE_CONTEXT pHc)
{
DWORD dwRetVal;
EnterCriticalSection(&(pHc->intrRegCriticalSection));
dwRetVal = READ_MMC_REGISTER_DWORD( pHc, MMC_IMASK );
LeaveCriticalSection(&(pHc->intrRegCriticalSection));
return dwRetVal;
}
__inline void READ_MOD_WRITE_MMC_IMASK_AND_OR(PSDH_HARDWARE_CONTEXT pHc, DWORD AndValue, DWORD OrValue)
{
EnterCriticalSection(&(pHc->intrRegCriticalSection));
READ_MOD_WRITE_MMC_REGISTER_AND_OR( pHc, MMC_IMASK, AndValue, OrValue );
LeaveCriticalSection(&(pHc->intrRegCriticalSection));
}
#define CLOCK_OFF_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_CLOCK_OFF_INT_MASKED)
// macro to turn SDIO interrupts on
#define SDIO_INTERRUPT_ON(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_SDIO_INT_MASKED, 0)
// macro to turn SDIO interrupts off
#define SDIO_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_SDIO_INT_MASKED)
// macro to turn RX FIFO interrupts on
#define RX_FIFO_INTERRUPT_ON(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_RXFIFO_REQ_INT_MASKED, 0)
// macro to turn RX FIFO interrupts off
#define RX_FIFO_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_RXFIFO_REQ_INT_MASKED)
// macro to turn TX FIFO interrupts on
#define TX_FIFO_INTERRUPT_ON(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_TXFIFO_REQ_INT_MASKED, 0)
// macro to turn TX FIFO interrupts off
#define TX_FIFO_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_TXFIFO_REQ_INT_MASKED)
#define TRANSFER_DONE_INTERRUPT_ON(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_DATA_TRAN_DONE_INT_MASKED, 0)
#define TRANSFER_DONE_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_DATA_TRAN_DONE_INT_MASKED)
#define END_CMD_INTERRUPT_ON(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_END_CMD_INT_MASKED, 0)
#define END_CMD_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_END_CMD_INT_MASKED)
#define PROGRAM_DONE_INTERRUPT_ON(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_PROG_DONE_INT_MASKED, 0)
#define PROGRAM_DONE_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_PROG_DONE_INT_MASKED)
#define PROGRAM_DATA_ERROR_INTERRUPT_ON(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_DATA_ERROR_INT_MASKED, 0)
#define PROGRAM_DATA_ERROR_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_DATA_ERROR_INT_MASKED)
#define PROGRAM_RESPONSE_ERROR_INTERRUPT_ON(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, ~MMC_IMASK_RESPONSE_ERROR_INT_MASKED, 0)
#define PROGRAM_RESPONSE_ERROR_INTERRUPT_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_RESPONSE_ERROR_INT_MASKED)
#define TX_BUFFER_PARTIAL_FULL(pHc) \
WRITE_MMC_REGISTER_DWORD(pHc, MMC_PRTBUF, MMC_PRTBUF_BUFFER_PARTIAL_FULL)
#define TX_BUFFER_PARTIAL_NOT_FULL(pHc) \
WRITE_MMC_REGISTER_DWORD(pHc, MMC_PRTBUF, 0)
#define ALL_INTERRUPTS_OFF(pHc) \
READ_MOD_WRITE_MMC_IMASK_AND_OR(pHc, 0xffffffff, MMC_IMASK_ALL_INTERRUPTS_MASKED)
// clock rate table
typedef struct _CLOCK_RATE_ENTRY {
DWORD Frequency;
UCHAR ControlValue;
} CLOCK_RATE_ENTRY, *PCLOCK_RATE_ENTRY;
CLOCK_RATE_ENTRY SDClockTable[] =
{ {312500, 0x06},
{625000, 0x05},
{1250000, 0x04},
{2500000, 0x03},
{5000000, 0x02},
{10000000, 0x01},
{20000000, 0x00}, // 20 Mhz
};
#define NUM_CLOCK_ENTRIES sizeof(SDClockTable)/sizeof(CLOCK_RATE_ENTRY)
///////////////////////////////////////////////////////////////////////////////
// SDClockOff - turn off the MMC clock
// Input: pHc - hardware context
// Output:
// Return:
// Notes:
//
///////////////////////////////////////////////////////////////////////////////
VOID SDClockOff(PSDH_HARDWARE_CONTEXT pHc)
{
// check to see if the clock is on
if (!CLOCK_IS_ON(pHc)) {
return;
}
DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("SDClockOff - turning off clock \n")));
// turn off the clock
WRITE_MMC_REGISTER_DWORD(pHc, MMC_STRPCL, MMC_STRPCL_STOP_CLOCK);
while (CLOCK_IS_ON(pHc)) {
// sit here and wait for the clock to turn off
DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("Waiting for clock off\n")));
}
DbgPrintZo(SDH_CLOCK_ZONE, (TEXT("SDClockOff - Clock is now off \n")));
}
///////////////////////////////////////////////////////////////////////////////
// SDClockOn - turn on the MMC Clock
// Input: pHc - hardware context
// Output:
// Return:
// Notes:
//
//
///////////////////////////////////////////////////////////////////////////////
VOID SDClockOn(PSDH_HARDWARE_CONTEXT pHc)
{
// turn on the clock
WRITE_MMC_REGISTER_DWORD(pHc, MMC_STRPCL, MMC_STRPCL_START_CLOCK);
}
///////////////////////////////////////////////////////////////////////////////
// SDClockOn - turn on the MMC Clock
// Input: pHc - hardware context
// pRate - pointer to desired clock rate in Hz
// Output:
// Return:
// Notes:
//
///////////////////////////////////////////////////////////////////////////////
VOID SDSetRate(PSDH_HARDWARE_CONTEXT pHc, PDWORD pRate)
{
ULONG ii; // table index variable
DWORD rate;
BOOL fClockRunning;
fClockRunning = CLOCK_IS_ON(pHc);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -