?? sdhcdma.cpp
字號:
//
// 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.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
SDHCDMA.cpp
Abstract:
Standard SDHC Driver DMA object implementation.
Notes:
--*/
#include "SDHC.h"
#include "sdhcdma.hpp"
#include "SDHCSlot.h"
CSDHCSlotBaseDMA::CSDHCSlotBaseDMA (CSDHCSlotBase& SDHCSloteBase)
: m_SDHCSloteBase (SDHCSloteBase)
{
m_dwNumOfList = 0;
m_dwNumOfAvailabe = 0;
m_pDmaBufferList = NULL;
m_dwCurDMAListPos = 0;
m_fDMAProcessing = FALSE;
m_dwDMACompletionCode = ERROR_SUCCESS;
m_hDma = NULL;
memset(&m_dmaAdapter,0,sizeof(m_dmaAdapter));
m_dmaAdapter.Size = sizeof(m_dmaAdapter);
m_dmaAdapter.BusMaster = TRUE;
m_dmaAdapter.BusNumber = m_SDHCSloteBase.m_dwBusNumber;
m_dmaAdapter.InterfaceType = m_SDHCSloteBase.m_interfaceType ;
};
BOOL CSDHCSlotBaseDMA::Init()
{
m_pDmaBufferList = new CE_DMA_BUFFER_BLOCK[INITIAL_DMA_LIST];
if (m_pDmaBufferList) {
m_dwNumOfList = INITIAL_DMA_LIST ;
}
return (m_pDmaBufferList!=NULL && m_dwNumOfList != 0);
}
CSDHCSlotBaseDMA::~CSDHCSlotBaseDMA()
{
if (m_pDmaBufferList)
delete [] m_pDmaBufferList;
if (m_hDma) {
DMACloseBuffer(m_hDma);
}
}
DWORD CSDHCSlotBaseDMA::ReAllocateDMABufferList(DWORD dwRequired)
{
if (m_pDmaBufferList && m_dwNumOfList < dwRequired) {
delete [] m_pDmaBufferList;
m_dwNumOfList = 0;
m_pDmaBufferList = NULL;
}
if (m_pDmaBufferList == NULL && dwRequired!= 0) {
m_pDmaBufferList = new CE_DMA_BUFFER_BLOCK[dwRequired];
if (m_pDmaBufferList) {
m_dwNumOfList = dwRequired;
}
else
{ // Allocation fail
m_dwNumOfList = 0;
}
}
return m_dwNumOfList;
}
BOOL CSDHCSlotBaseDMA::CancelDMA()
{
if (!m_fDMAProcessing) {
m_fDMAProcessing = FALSE;
m_dwCurDMAListPos = m_dwNumOfAvailabe;
m_dwDMACompletionCode = ERROR_CANCELLED ;
}
if (!m_fDMAProcessing && m_hDma) {
DMACloseBuffer(m_hDma);
m_hDma = NULL;
}
return TRUE;
}
BOOL CSDHCSlotBaseDMA::ArmDMA(SD_BUS_REQUEST& Request,BOOL fToDevice)
{
ASSERT(!m_fDMAProcessing);
ASSERT(m_hDma==NULL);
BOOL fReturn = FALSE;
// Check for the limitaion.
if (Request.NumBlocks > 1 && (Request.BlockSize & (sizeof(DWORD)-1)) == 0
&& ((DWORD)Request.pBlockBuffer & (sizeof(DWORD)-1)) == 0
&& m_hDma == NULL) {
// We are going to transfer this block as DMA.
if ( (Request.Flags & SD_BUS_REQUEST_PHYS_BUFFER)!=0 &&
Request.cbSizeOfPhysList!=0 && Request.pPhysBuffList!=NULL) {
// We have user passed in Physical Buffer List.
if (ReAllocateDMABufferList(Request.cbSizeOfPhysList) >= Request.cbSizeOfPhysList) {
//Copy the Buffer.
ASSERT(Request.cbSizeOfPhysList <= m_dwNumOfList);
m_dwNumOfAvailabe = Request.cbSizeOfPhysList ;
PBYTE pVirtualAddr = Request.pBlockBuffer ;
for (DWORD dwIndex = 0; dwIndex < Request.cbSizeOfPhysList && dwIndex< m_dwNumOfList; dwIndex ++) {
m_pDmaBufferList[dwIndex].dwLength = Request.pPhysBuffList[dwIndex].PhysLen;
m_pDmaBufferList[dwIndex].physicalAddress = Request.pPhysBuffList[dwIndex].PhysAddr;
m_pDmaBufferList[dwIndex].virtualAddress = pVirtualAddr + m_pDmaBufferList[dwIndex].dwLength;
}
fReturn = TRUE;
}
}
else { // We need figure out the physical address by using CEDDK DMA function.
DWORD dwLength = Request.BlockSize * Request.NumBlocks;
m_dmaAdapter.dwFlags =(fToDevice? DMA_FLAGS_WRITE_TO_DEVICE: 0);
// if (!fToDevice) {
// memset(Request.pBlockBuffer,0xc5,dwLength);
// }
m_hDma = DMAOpenBuffer(&m_dmaAdapter,1, (PVOID *)&Request.pBlockBuffer,&dwLength);
if (m_hDma) {
m_dwNumOfAvailabe = DMAGetBufferPhysAddr(m_hDma, m_dwNumOfList, m_pDmaBufferList);
if (m_dwNumOfAvailabe>m_dwNumOfList && ReAllocateDMABufferList(m_dwNumOfAvailabe)>=m_dwNumOfAvailabe) {
m_dwNumOfAvailabe = DMAGetBufferPhysAddr(m_hDma, m_dwNumOfList, m_pDmaBufferList);
}
if (m_dwNumOfAvailabe<= m_dwNumOfList) {
fReturn = TRUE;
}
else { // FAILED.
m_dwNumOfAvailabe = 0;
DMACloseBuffer(m_hDma);
m_hDma = NULL;
}
}
}
ASSERT(fReturn);
}
return fReturn;
}
CSDHCSlotBaseSDMA::~CSDHCSlotBaseSDMA()
{
if (m_StartBuffer.pBufferedVirtualAddr!=NULL) {
OALDMAFreeBuffer(&m_dmaAdapter, PAGE_SIZE,m_StartBuffer.physicalAddress,m_StartBuffer.pBufferedVirtualAddr,FALSE);
//OALDMAFreeBuffer(&m_dmaAdapter, PAGE_SIZE*128,m_StartBuffer.physicalAddress,m_StartBuffer.pBufferedVirtualAddr,FALSE);
}
if (m_EndBuffer.pBufferedVirtualAddr!=NULL) {
OALDMAFreeBuffer(&m_dmaAdapter, PAGE_SIZE,m_EndBuffer.physicalAddress,m_EndBuffer.pBufferedVirtualAddr,FALSE);
//OALDMAFreeBuffer(&m_dmaAdapter, PAGE_SIZE*128,m_EndBuffer.physicalAddress,m_EndBuffer.pBufferedVirtualAddr,FALSE);
}
if (m_fLocked )
UnlockPages( m_lpvLockedAddress, m_dwLockedSize);
m_fLocked = FALSE;
}
BOOL CSDHCSlotBaseSDMA::Init()
{
m_fLocked= FALSE;
if (!CeGetCacheInfo(sizeof(m_ceCacheInfo), &m_ceCacheInfo)) {
ASSERT(FALSE);
return FALSE;
}
else {
m_StartBuffer.pBufferedVirtualAddr = OALDMAAllocBuffer(&m_dmaAdapter, PAGE_SIZE , &m_StartBuffer.physicalAddress, FALSE );
m_StartBuffer.dwBufferOffset = 0;
m_StartBuffer.dwBufferSize = PAGE_SIZE;
m_StartBuffer.pSrcVirtualAddr = NULL;
m_StartBuffer.pSrcSize = 0;
m_EndBuffer.pBufferedVirtualAddr = OALDMAAllocBuffer(&m_dmaAdapter, PAGE_SIZE , &m_EndBuffer.physicalAddress, FALSE );
m_EndBuffer.dwBufferOffset = 0;
m_EndBuffer.dwBufferSize = PAGE_SIZE;
m_EndBuffer.pSrcVirtualAddr = NULL;
m_EndBuffer.pSrcSize = 0;
return (m_StartBuffer.pBufferedVirtualAddr!=NULL && m_EndBuffer.pBufferedVirtualAddr!=NULL && CSDHCSlotBaseDMA::Init());
}
};
BOOL CSDHCSlotBaseSDMA::GetDMABuffer(SD_BUS_REQUEST& Request,BOOL fToDevice)
{
// We shouldn't use PAGE_SHIFT in CEDDK because it is too confusing and too dangerouse.
#define PFN_SHIEFT UserKInfo[KINX_PFN_SHIFT]
#define MAX_SUPPORTED_PFN (MAXDWORD>>PFN_SHIEFT)
#define PAGE_MASK (PAGE_SIZE-1)
ASSERT(!m_fDMAProcessing);
ASSERT(m_hDma==NULL);
ASSERT(m_fLocked == FALSE);
m_StartBuffer.pSrcVirtualAddr = NULL;
m_StartBuffer.pSrcSize = 0;
m_EndBuffer.pSrcVirtualAddr = NULL;
m_EndBuffer.pSrcSize = 0;
BOOL fReturn = FALSE;
// Check for the limitaion.
if (Request.NumBlocks > 1 && (Request.BlockSize & (sizeof(DWORD)-1)) == 0
&& ((DWORD)Request.pBlockBuffer & (sizeof(DWORD)-1)) == 0
&& m_hDma == NULL) {
// We are going to transfer this block as DMA.
if ( (Request.Flags & SD_BUS_REQUEST_PHYS_BUFFER)!=0 &&
Request.cbSizeOfPhysList!=0 && Request.pPhysBuffList!=NULL) {
// We have user passed in Physical Buffer List.
if (ReAllocateDMABufferList(Request.cbSizeOfPhysList) >= Request.cbSizeOfPhysList) {
//Copy the Buffer.
ASSERT(Request.cbSizeOfPhysList <= m_dwNumOfList);
m_dwNumOfAvailabe = Request.cbSizeOfPhysList ;
PBYTE pVirtualAddr = Request.pBlockBuffer ;
for (DWORD dwIndex = 0; dwIndex < Request.cbSizeOfPhysList && dwIndex< m_dwNumOfList; dwIndex ++) {
m_pDmaBufferList[dwIndex].dwLength = Request.pPhysBuffList[dwIndex].PhysLen;
m_pDmaBufferList[dwIndex].physicalAddress = Request.pPhysBuffList[dwIndex].PhysAddr;
m_pDmaBufferList[dwIndex].virtualAddress = pVirtualAddr + m_pDmaBufferList[dwIndex].dwLength;
}
fReturn = TRUE;
}
}
else { // We need figure out the physical address by using CEDDK DMA function.
DWORD dwLength = Request.BlockSize * Request.NumBlocks;
PVOID pUseBufferPtr = Request.pBlockBuffer;
m_dmaAdapter.dwFlags =(fToDevice? DMA_FLAGS_WRITE_TO_DEVICE: 0);
// if (!fToDevice) {
// memset(Request.pBlockBuffer,0xc5,dwLength);
// }
m_dwNumOfAvailabe = ADDRESS_AND_SIZE_TO_SPAN_PAGES( pUseBufferPtr, dwLength );
PDWORD pdwPhysAddress = new DWORD[m_dwNumOfAvailabe];
if (pdwPhysAddress) {
if (m_dwNumOfAvailabe> m_dwNumOfList) {
ReAllocateDMABufferList(m_dwNumOfAvailabe);
}
if (m_dwNumOfAvailabe<= m_dwNumOfList ) {
m_fLocked = LockPages( pUseBufferPtr,dwLength,pdwPhysAddress, // m_pdwPhysAddress to stall PFN temperory.
fToDevice? LOCKFLAG_READ: LOCKFLAG_WRITE);
if (m_fLocked) { // Create table for Physical Address and length.
m_lpvLockedAddress = pUseBufferPtr;
m_dwLockedSize = dwLength;
fReturn = TRUE;
for (DWORD dwIndex = 0; dwIndex< m_dwNumOfAvailabe; dwIndex++) {
if (pdwPhysAddress[dwIndex] > MAX_SUPPORTED_PFN) {
ASSERT(FALSE);
fReturn = FALSE;
break;
}
else {
m_pDmaBufferList[dwIndex].dwLength = min((PAGE_SIZE - ((DWORD)pUseBufferPtr & PAGE_MASK)),dwLength);
m_pDmaBufferList[dwIndex].physicalAddress.LowPart = (pdwPhysAddress[dwIndex]<<PFN_SHIEFT) + ((DWORD)pUseBufferPtr & PAGE_MASK);
m_pDmaBufferList[dwIndex].physicalAddress.HighPart = 0;
m_pDmaBufferList[dwIndex].virtualAddress = (PBYTE)pUseBufferPtr;
dwLength -= m_pDmaBufferList[dwIndex].dwLength;
pUseBufferPtr = (PBYTE)pUseBufferPtr+m_pDmaBufferList[dwIndex].dwLength;
}
};
}
}
delete [] pdwPhysAddress;
}
if (fReturn && m_dwNumOfAvailabe) { // Check for Cache aligh begin and end.
if (!fToDevice) {
DWORD dwDCacheLineSize = GetDataCacheSize() ;
ASSERT ((dwDCacheLineSize & dwDCacheLineSize-1) == 0 ); // I has to be nature align.
// First Block
if ((m_pDmaBufferList[0].physicalAddress.LowPart & (dwDCacheLineSize-1)) != 0) { // Not cache align. we have to do something.
m_StartBuffer.dwBufferOffset = (m_pDmaBufferList[0].physicalAddress.LowPart & PAGE_MASK);
m_StartBuffer.pSrcSize = m_pDmaBufferList[0].dwLength;
m_StartBuffer.pSrcVirtualAddr = m_pDmaBufferList[0].virtualAddress;
m_pDmaBufferList[0].physicalAddress.QuadPart = m_StartBuffer.physicalAddress.QuadPart + m_StartBuffer.dwBufferOffset;
//m_pDmaBufferList[0].virtualAddress = (PBYTE)m_StartBuffer.pBufferedVirtualAddr + m_StartBuffer.dwBufferOffset;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -