ddk_map.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 323 行
C
323 行
/*++
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.
Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
Module Name:
ddk_map.c
Abstract:
WINCE device driver support routines. This file supports
a very minimal subset of the routines from ntddk.h
Functions:
Notes:
--*/
#include <windows.h>
#include <types.h>
#include "ceddk.h"
#define VERBOSE 0
/*++
Routine Description:
map the given physical address range to nonpaged system space
Arguments:
PhysicalAddress - starting physical address of the I/O range to be mapped
NumberOfBytes - number of bytes to be mapped
CacheEnable - TRUE if the physical address range can be mapped as cached
memory
Return Value:
base virtual address that maps the base physical address for the range, or
NULL if space for mapping the range is insufficient
--*/
PVOID
MmMapIoSpace (
IN PHYSICAL_ADDRESS PhysicalAddress,
IN ULONG NumberOfBytes,
IN BOOLEAN CacheEnable
)
{
PVOID pVirtualAddress;
ULONG SourcePhys;
ULONG SourceSize;
BOOL bSuccess;
//
// Page align source and adjust size to compensate
//
SourcePhys = PhysicalAddress.LowPart & ~(PAGE_SIZE - 1);
SourceSize = NumberOfBytes + (PhysicalAddress.LowPart & (PAGE_SIZE - 1));
pVirtualAddress = VirtualAlloc(0, SourceSize, MEM_RESERVE, PAGE_NOACCESS);
if ( pVirtualAddress != NULL ) {
bSuccess = VirtualCopy(
pVirtualAddress, (PVOID)(SourcePhys >> 8), SourceSize,
PAGE_PHYSICAL | PAGE_READWRITE | (CacheEnable ? 0 : PAGE_NOCACHE));
if ( bSuccess ) {
(ULONG)pVirtualAddress += PhysicalAddress.LowPart & (PAGE_SIZE - 1);
} else {
VirtualFree(pVirtualAddress, SourceSize, MEM_RELEASE);
pVirtualAddress = NULL;
}
}
return (pVirtualAddress);
}
/*++
Routine Description:
unmap a specified range of physical addresses previously mapped by
MmMapIoSpace
Arguments:
BaseAddress - pointer to the base virtual address to which the physical
pages were mapped
NumberOfBytes - number of bytes that were mapped
Return Value:
None
--*/
VOID
MmUnmapIoSpace (
IN PVOID BaseAddress,
IN ULONG NumberOfBytes
)
{
PVOID pVirtualAddress = (PVOID)((ULONG)BaseAddress & ~(ULONG)(PAGE_SIZE - 1));
ULONG SourceSize = NumberOfBytes + ((ULONG)BaseAddress & (PAGE_SIZE - 1));
VirtualFree(pVirtualAddress, SourceSize, MEM_RELEASE);
}
/*++
CeAllocPhysMem:
Allocates a contiguous physical buffer on a page boundary so that it is simultaneously
accessible from both the processor and a device for DMA operations.
This routine is similar to the NTDDK's HalAllocateCommonBuffer, but WinCE does not support Adapter Objects.
Arguments:
StartAddress - Specifies the desired starting address of the region to allocate.
Usually NULL unless the device requires a specific start address.
Length - Specifies the number of bytes to allocate.
PhysicalAddress - Points to a variable that receives the physical address the
device can use to access the allocated buffer.
CacheEnabled - Specifies whether the allocated memory should be cached;
usually FALSE for drivers
Return Value:
Base virtual address of the allocated range if successful, else NULL.
Notes:
If a driver needs several pages of physical buffer space, but the pages need not be contiguous, the driver should make several
one-page requests rather than one large request. This approach conserves contiguous memory.
Drivers typically call this routine during device initialization. After initialization, it is possible that only
one-page requests will succeed, if any.
Memory can be released by calling CeFreePhysMem.
--*/
LPVOID
CeAllocPhysMem(
IN LPVOID StartAddress,
IN ULONG Length,
OUT PULONG PhysicalAddress,
IN BOOLEAN CacheEnabled
)
{
LPVOID pVirtualBuffer = NULL;
LPVOID pLastBuffer;
LPVOID pNextBuffer;
ULONG paBuffer = 0;
BOOL fDone;
BOOL fLocked;
UINT nPages;
PULONG pPFNs;
UINT i;
if( !Length || !PhysicalAddress ) {
DEBUGMSG(1, (TEXT("CeAllocPhysMem - invalid parameter\n")));
return NULL;
} else {
//
// find the maximum # of pages to be locked
//
nPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( NULL, Length );
//
// allocate an array of page Physical Frame Numbers
// representing the CPU-dependent physical addresses of the pages.
//
pPFNs = LocalAlloc( LPTR, sizeof(ULONG) * nPages );
if ( !pPFNs ) {
DEBUGMSG(1, (TEXT("CeAllocPhysMem - LocalAlloc Error:%d\n"), GetLastError() ));
return NULL;
}
}
do {
fDone = TRUE;
pLastBuffer = pVirtualBuffer;
//
// allocate physical storage in memory, or paging file
//
pVirtualBuffer = VirtualAlloc( StartAddress,
Length,
MEM_COMMIT,
CacheEnabled ? PAGE_READWRITE : (PAGE_NOCACHE | PAGE_READWRITE) );
// our allocated block must be on a page boundary!
ASSERT(((DWORD)pVirtualBuffer & (PAGE_SIZE - 1)) == 0);
if( pVirtualBuffer ) {
//
// lock into physical memory the specified region of
// virtual address space of the process, ensuring that
// subsequent access to the region will not incur a page fault.
//
fLocked = LockPages( pVirtualBuffer,
Length,
pPFNs,
LOCKFLAG_WRITE );
if ( fLocked ) {
//
// To determine the actual physical address,
// the value returned in pPFNs must be right-shifted by a number of bits.
// The shift count can be found in UserKInfo[KINX_PFN_SHIFT].
// Right shift the returned values by UserKInfo[KINX_PFN_SHIFT] to get the actual physical address.
//
PULONG pPage;
ASSERT( ADDRESS_AND_SIZE_TO_SPAN_PAGES(pVirtualBuffer, Length) == nPages );
//
// We want page numbers and NK gives us the physical address
// of each page, adjust the list. Except on MIPS where NK
// gives us the physical address shifted right 6 bits.
//
for (i = 0, pPage = pPFNs; i < nPages ; ++i )
{
#if defined(MIPS)
#if defined(R4000) | defined(R5230)
#if defined(R4100)
*pPage >>= PAGE_SHIFT - 4;
#else
*pPage >>= PAGE_SHIFT - 6;
#endif
#else
*pPage >>= PAGE_SHIFT;
#endif
#elif defined(SHx) | defined(x86) | defined(PPC) | defined(ARM)
*pPage >>= PAGE_SHIFT;
#else
#error Unsupported Processor
#endif
++pPage;
}
ASSERT( nPages > 0 );
for(i = 0, pPage = pPFNs ; i < nPages - 1 && fDone ; ++i)
{
if(*pPage + 1 != *(pPage + 1))
fDone = FALSE;
++pPage;
}
if(fDone)
paBuffer = *pPFNs << PAGE_SHIFT;
} else {
DEBUGMSG(1, (TEXT("CeAllocPhysMem - VirtualLock Error: %d\n"), GetLastError()));
}
if( !fDone ) {
*(LPVOID *)pVirtualBuffer = pLastBuffer;
}
} else {
DEBUGMSG(VERBOSE, (TEXT("CeAllocPhysMem - VirtualAlloc Error: %d\n"),GetLastError()));
}
} while(!fDone);
while(pLastBuffer)
{
pNextBuffer = *(LPVOID *)pLastBuffer;
UnlockPages(pLastBuffer, Length);
VirtualFree(pLastBuffer,0, MEM_RELEASE);
pLastBuffer = pNextBuffer;
}
// our allocated block must be on a page boundary or we will miss
// part of the physical address and the interrupt table will not be aligned!
ASSERT(((DWORD)pVirtualBuffer & (PAGE_SIZE - 1)) == 0);
ASSERT((paBuffer & (PAGE_SIZE - 1)) == 0);
ASSERT(PhysicalAddress);
*PhysicalAddress = paBuffer;
if(pPFNs)
LocalFree(pPFNs);
DEBUGMSG(VERBOSE, (TEXT("CeAllocPhysMem - VA: %08X PA:%08X \r\n"), pVirtualBuffer, paBuffer));
return pVirtualBuffer;
}
/*
Release memory previously acquired with CeAllocPhysMem.
*/
ULONG
CeFreePhysMem(
IN PVOID VirtualAddress,
IN ULONG Length
)
{
ULONG status = STATUS_SUCCESS;
if ( !UnlockPages( VirtualAddress, Length ) ) {
status = GetLastError();
DEBUGMSG(1, (TEXT("CeAllocPhysMem - UnlockPages Error:%d\n"), status ));
}
if ( !VirtualFree( VirtualAddress,0, MEM_RELEASE) ) {
status = GetLastError();
DEBUGMSG(1, (TEXT("CeAllocPhysMem - VirtualFree Error:%d\n"), status ));
}
return status;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?